nginx 时间初始化

2014-12-26 16:35:44   最后更新: 2014-12-26 16:35:44   访问数量:1288




nginx 启动后首先进行的是参数的校验和相关操作,这里不过多的介绍了,直接进入正题

 

时间初始化及各种相关设置的函数和变量都在 core/ngx_times.c 文件中,下面我们介绍的是其中的两个:ngx_time_init 和 ngx_time_update,分别用来初始化和更新几个全局时间变量

// void ngx_time_init(void) // 初始化时间字符串 {{{ void ngx_time_init(void) { ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1; ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1; ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1; ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1; ngx_cached_time = &cached_time[0]; ngx_time_update(); } // }}} // void ngx_time_update(void) // 更新当前时间结构 {{{ void ngx_time_update(void) { u_char *p0, *p1, *p2, *p3, *p4; /* * ngx_tm_t 是 struct tm 的别名 * struct tm { * int tm_sec; // 秒–取值区间为[0,59] * int tm_min; // 分 - 取值区间为[0,59] * int tm_hour; // 时 - 取值区间为[0,23] * int tm_mday; // 一个月中的日期 - 取值区间为[1,31] * int tm_mon; // 月份(从一月开始,0代表一月) - 取值区间为[0,11] * int tm_year; // 年份,其值从1900开始 * int tm_wday; // 星期–取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 * int tm_yday; // 从每年的1月1日开始的天数–取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 * int tm_isdst; // 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负。 * long int tm_gmtoff; // 指定了日期变更线东面时区中UTC东部时区正秒数或UTC西部时区的负秒数 * const char *tm_zone; // 当前时区的名字(与环境变量TZ有关) * } */ ngx_tm_t tm, gmt; time_t sec; ngx_uint_t msec; /* * typedef struct { * time_t sec; * ngx_uint_t msec; * ngx_int_t gmtoff; * } ngx_time_t; */ ngx_time_t *tp; /* * struct timeval { * long tv_sec; // seconds * long tv_usec; // and microseconds * }; */ struct timeval tv; // 尝试锁住互斥锁 if (!ngx_trylock(&ngx_time_lock)) { return; } // linux 与 windows 分别使用不同的函数获取当前时间 // 使用该宏进行封装 ngx_gettimeofday(&tv); sec = tv.tv_sec; msec = tv.tv_usec / 1000; ngx_current_msec = (ngx_msec_t) sec * 1000 + msec; tp = &cached_time[slot]; // 完全相同则不必更新 if (tp->sec == sec) { tp->msec = msec; ngx_unlock(&ngx_time_lock); return; } if (slot == NGX_TIME_SLOTS - 1) { slot = 0; } else { slot++; } // 每调用一次 ngx_time_update 保存一次时间 tp = &cached_time[slot]; tp->sec = sec; tp->msec = msec; // 将 sec 的时间戳转换为 gmt 的结构 ngx_gmtime(sec, &gmt); // 把时间转为http格式的时间字符串,p0就设置为诸如“Fri, 27 Jul 2012 01:09:17 GMT” p0 = &cached_http_time[slot][0]; // ngx_sprintf -> ngx_string.c 需要详细了解一下 (void) ngx_sprintf(p0, "%s, %02d %s %4d %02d:%02d:%02d GMT", week[gmt.ngx_tm_wday], gmt.ngx_tm_mday, months[gmt.ngx_tm_mon - 1], gmt.ngx_tm_year, gmt.ngx_tm_hour, gmt.ngx_tm_min, gmt.ngx_tm_sec); // 获取时区带来的时间差 #if (NGX_HAVE_GETTIMEZONE) tp->gmtoff = ngx_gettimezone(); ngx_gmtime(sec + tp->gmtoff * 60, &tm); #elif (NGX_HAVE_GMTOFF) ngx_localtime(sec, &tm); cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60); tp->gmtoff = cached_gmtoff; #else ngx_localtime(sec, &tm); cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst); tp->gmtoff = cached_gmtoff; #endif p1 = &cached_err_log_time[slot][0]; (void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d", tm.ngx_tm_year, tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); p2 = &cached_http_log_time[slot][0]; (void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d", tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1], tm.ngx_tm_year, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec, tp->gmtoff < 0 ? '-' : '+', ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60)); p3 = &cached_http_log_iso8601[slot][0]; (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", tm.ngx_tm_year, tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec, tp->gmtoff < 0 ? '-' : '+', ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60)); p4 = &cached_syslog_time[slot][0]; (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d", months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); ngx_memory_barrier(); ngx_cached_time = tp; ngx_cached_http_time.data = p0; ngx_cached_err_log_time.data = p1; ngx_cached_http_log_time.data = p2; ngx_cached_http_log_iso8601.data = p3; ngx_cached_syslog_time.data = p4; ngx_unlock(&ngx_time_lock); } // }}}

 

执行结束后,各个全局变量取值:

nginx 时间初始化后变量取值
全局变量取值说明
ngx_cached_err_log_time{len = 19, data = "2014/12/26 14:57:19"}所有log所使用的时间
ngx_cached_http_time{len = 29, data = "Fri, 26 Dec 2014 06:57:19 GMT"}http协议中的时间格式
ngx_cached_http_log_time{len = 26, data = "26/Dec/2014:14:57:19 +0800"}accesse.log中的时间格式
ngx_cached_http_log_iso8601{len = 25, data = "2014-12-26T14:57:19+08:00"}http缓存log时间级iso8061时间
ngx_cached_syslog_time{len = 15, data = "2014-12-26T14:57:19+08:00"}系统时间
ngx_cached_time0x80e4e20 {(ngx_time_t *)cache_time->{sec = 1419577039, msec = 680, gmtoff = 480}}指向当前时间的cached_time(64格散列,保存多次操作的时间)
slot1散列时间表当前index+1

 

首次执行,调用 ngx_time_init 函数初始化几个全局时间变量,然后使用 ngx_time_update 函数更新时间值

在此后的调用中,只需调用 ngx_time_update 即可

时间会被放置于:

cached_time、cached_err_log_time、cached_http_time、cached_http_log_time、cached_http_log_iso8601、cached_syslog_time

等数组中,使用 slot-1 作为下标引用

当前时间字符串保存在 ngx_cached_err_log_time、ngx_cached_http_time、ngx_cached_http_log_time、ngx_cached_http_log_iso8601、ngx_cached_syslog_time 几个结构中

 

这里用到了一个结构体 ngx_str_t

nginx 有关字符串的变量及函数都存储在 core/ngx_string.h 与 core/ngx_string.c 中

// struct ngx_str_t // string 类型 {{{ typedef struct { size_t len; u_char *data; } ngx_str_t; // }}}

 

规避了C语言中字符串必须以 \0 结尾可能引发的各种问题

 

至于围绕 ngx_str_t 类型的各种操作函数,我们将在后面遇到的时候进行详细介绍

 






技术帖      linux      unix      c语言      龙潭书斋      time      nginx      tm      time_t     


京ICP备15018585号