Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 
0011 
0012 static ngx_msec_t ngx_monotonic_time(time_t sec, ngx_uint_t msec);
0013 
0014 
0015 /*
0016  * The time may be updated by signal handler or by several threads.
0017  * The time update operations are rare and require to hold the ngx_time_lock.
0018  * The time read operations are frequent, so they are lock-free and get time
0019  * values and strings from the current slot.  Thus thread may get the corrupted
0020  * values only if it is preempted while copying and then it is not scheduled
0021  * to run more than NGX_TIME_SLOTS seconds.
0022  */
0023 
0024 #define NGX_TIME_SLOTS   64
0025 
0026 static ngx_uint_t        slot;
0027 static ngx_atomic_t      ngx_time_lock;
0028 
0029 volatile ngx_msec_t      ngx_current_msec;
0030 volatile ngx_time_t     *ngx_cached_time;
0031 volatile ngx_str_t       ngx_cached_err_log_time;
0032 volatile ngx_str_t       ngx_cached_http_time;
0033 volatile ngx_str_t       ngx_cached_http_log_time;
0034 volatile ngx_str_t       ngx_cached_http_log_iso8601;
0035 volatile ngx_str_t       ngx_cached_syslog_time;
0036 
0037 #if !(NGX_WIN32)
0038 
0039 /*
0040  * localtime() and localtime_r() are not Async-Signal-Safe functions, therefore,
0041  * they must not be called by a signal handler, so we use the cached
0042  * GMT offset value. Fortunately the value is changed only two times a year.
0043  */
0044 
0045 static ngx_int_t         cached_gmtoff;
0046 #endif
0047 
0048 static ngx_time_t        cached_time[NGX_TIME_SLOTS];
0049 static u_char            cached_err_log_time[NGX_TIME_SLOTS]
0050                                     [sizeof("1970/09/28 12:00:00")];
0051 static u_char            cached_http_time[NGX_TIME_SLOTS]
0052                                     [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
0053 static u_char            cached_http_log_time[NGX_TIME_SLOTS]
0054                                     [sizeof("28/Sep/1970:12:00:00 +0600")];
0055 static u_char            cached_http_log_iso8601[NGX_TIME_SLOTS]
0056                                     [sizeof("1970-09-28T12:00:00+06:00")];
0057 static u_char            cached_syslog_time[NGX_TIME_SLOTS]
0058                                     [sizeof("Sep 28 12:00:00")];
0059 
0060 
0061 static char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
0062 static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
0063                            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
0064 
0065 void
0066 ngx_time_init(void)
0067 {
0068     ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
0069     ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
0070     ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
0071     ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
0072     ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1;
0073 
0074     ngx_cached_time = &cached_time[0];
0075 
0076     ngx_time_update();
0077 }
0078 
0079 
0080 void
0081 ngx_time_update(void)
0082 {
0083     u_char          *p0, *p1, *p2, *p3, *p4;
0084     ngx_tm_t         tm, gmt;
0085     time_t           sec;
0086     ngx_uint_t       msec;
0087     ngx_time_t      *tp;
0088     struct timeval   tv;
0089 
0090     if (!ngx_trylock(&ngx_time_lock)) {
0091         return;
0092     }
0093 
0094     ngx_gettimeofday(&tv);
0095 
0096     sec = tv.tv_sec;
0097     msec = tv.tv_usec / 1000;
0098 
0099     ngx_current_msec = ngx_monotonic_time(sec, msec);
0100 
0101     tp = &cached_time[slot];
0102 
0103     if (tp->sec == sec) {
0104         tp->msec = msec;
0105         ngx_unlock(&ngx_time_lock);
0106         return;
0107     }
0108 
0109     if (slot == NGX_TIME_SLOTS - 1) {
0110         slot = 0;
0111     } else {
0112         slot++;
0113     }
0114 
0115     tp = &cached_time[slot];
0116 
0117     tp->sec = sec;
0118     tp->msec = msec;
0119 
0120     ngx_gmtime(sec, &gmt);
0121 
0122 
0123     p0 = &cached_http_time[slot][0];
0124 
0125     (void) ngx_sprintf(p0, "%s, %02d %s %4d %02d:%02d:%02d GMT",
0126                        week[gmt.ngx_tm_wday], gmt.ngx_tm_mday,
0127                        months[gmt.ngx_tm_mon - 1], gmt.ngx_tm_year,
0128                        gmt.ngx_tm_hour, gmt.ngx_tm_min, gmt.ngx_tm_sec);
0129 
0130 #if (NGX_HAVE_GETTIMEZONE)
0131 
0132     tp->gmtoff = ngx_gettimezone();
0133     ngx_gmtime(sec + tp->gmtoff * 60, &tm);
0134 
0135 #elif (NGX_HAVE_GMTOFF)
0136 
0137     ngx_localtime(sec, &tm);
0138     cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
0139     tp->gmtoff = cached_gmtoff;
0140 
0141 #else
0142 
0143     ngx_localtime(sec, &tm);
0144     cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst);
0145     tp->gmtoff = cached_gmtoff;
0146 
0147 #endif
0148 
0149 
0150     p1 = &cached_err_log_time[slot][0];
0151 
0152     (void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d",
0153                        tm.ngx_tm_year, tm.ngx_tm_mon,
0154                        tm.ngx_tm_mday, tm.ngx_tm_hour,
0155                        tm.ngx_tm_min, tm.ngx_tm_sec);
0156 
0157 
0158     p2 = &cached_http_log_time[slot][0];
0159 
0160     (void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02i%02i",
0161                        tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
0162                        tm.ngx_tm_year, tm.ngx_tm_hour,
0163                        tm.ngx_tm_min, tm.ngx_tm_sec,
0164                        tp->gmtoff < 0 ? '-' : '+',
0165                        ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
0166 
0167     p3 = &cached_http_log_iso8601[slot][0];
0168 
0169     (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i",
0170                        tm.ngx_tm_year, tm.ngx_tm_mon,
0171                        tm.ngx_tm_mday, tm.ngx_tm_hour,
0172                        tm.ngx_tm_min, tm.ngx_tm_sec,
0173                        tp->gmtoff < 0 ? '-' : '+',
0174                        ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
0175 
0176     p4 = &cached_syslog_time[slot][0];
0177 
0178     (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d",
0179                        months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
0180                        tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
0181 
0182     ngx_memory_barrier();
0183 
0184     ngx_cached_time = tp;
0185     ngx_cached_http_time.data = p0;
0186     ngx_cached_err_log_time.data = p1;
0187     ngx_cached_http_log_time.data = p2;
0188     ngx_cached_http_log_iso8601.data = p3;
0189     ngx_cached_syslog_time.data = p4;
0190 
0191     ngx_unlock(&ngx_time_lock);
0192 }
0193 
0194 
0195 static ngx_msec_t
0196 ngx_monotonic_time(time_t sec, ngx_uint_t msec)
0197 {
0198 #if (NGX_HAVE_CLOCK_MONOTONIC)
0199     struct timespec  ts;
0200 
0201 #if defined(CLOCK_MONOTONIC_FAST)
0202     clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
0203 
0204 #elif defined(CLOCK_MONOTONIC_COARSE)
0205     clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
0206 
0207 #else
0208     clock_gettime(CLOCK_MONOTONIC, &ts);
0209 #endif
0210 
0211     sec = ts.tv_sec;
0212     msec = ts.tv_nsec / 1000000;
0213 
0214 #endif
0215 
0216     return (ngx_msec_t) sec * 1000 + msec;
0217 }
0218 
0219 
0220 #if !(NGX_WIN32)
0221 
0222 void
0223 ngx_time_sigsafe_update(void)
0224 {
0225     u_char          *p, *p2;
0226     ngx_tm_t         tm;
0227     time_t           sec;
0228     ngx_time_t      *tp;
0229     struct timeval   tv;
0230 
0231     if (!ngx_trylock(&ngx_time_lock)) {
0232         return;
0233     }
0234 
0235     ngx_gettimeofday(&tv);
0236 
0237     sec = tv.tv_sec;
0238 
0239     tp = &cached_time[slot];
0240 
0241     if (tp->sec == sec) {
0242         ngx_unlock(&ngx_time_lock);
0243         return;
0244     }
0245 
0246     if (slot == NGX_TIME_SLOTS - 1) {
0247         slot = 0;
0248     } else {
0249         slot++;
0250     }
0251 
0252     tp = &cached_time[slot];
0253 
0254     tp->sec = 0;
0255 
0256     ngx_gmtime(sec + cached_gmtoff * 60, &tm);
0257 
0258     p = &cached_err_log_time[slot][0];
0259 
0260     (void) ngx_sprintf(p, "%4d/%02d/%02d %02d:%02d:%02d",
0261                        tm.ngx_tm_year, tm.ngx_tm_mon,
0262                        tm.ngx_tm_mday, tm.ngx_tm_hour,
0263                        tm.ngx_tm_min, tm.ngx_tm_sec);
0264 
0265     p2 = &cached_syslog_time[slot][0];
0266 
0267     (void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d",
0268                        months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
0269                        tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
0270 
0271     ngx_memory_barrier();
0272 
0273     ngx_cached_err_log_time.data = p;
0274     ngx_cached_syslog_time.data = p2;
0275 
0276     ngx_unlock(&ngx_time_lock);
0277 }
0278 
0279 #endif
0280 
0281 
0282 u_char *
0283 ngx_http_time(u_char *buf, time_t t)
0284 {
0285     ngx_tm_t  tm;
0286 
0287     ngx_gmtime(t, &tm);
0288 
0289     return ngx_sprintf(buf, "%s, %02d %s %4d %02d:%02d:%02d GMT",
0290                        week[tm.ngx_tm_wday],
0291                        tm.ngx_tm_mday,
0292                        months[tm.ngx_tm_mon - 1],
0293                        tm.ngx_tm_year,
0294                        tm.ngx_tm_hour,
0295                        tm.ngx_tm_min,
0296                        tm.ngx_tm_sec);
0297 }
0298 
0299 
0300 u_char *
0301 ngx_http_cookie_time(u_char *buf, time_t t)
0302 {
0303     ngx_tm_t  tm;
0304 
0305     ngx_gmtime(t, &tm);
0306 
0307     /*
0308      * Netscape 3.x does not understand 4-digit years at all and
0309      * 2-digit years more than "37"
0310      */
0311 
0312     return ngx_sprintf(buf,
0313                        (tm.ngx_tm_year > 2037) ?
0314                                          "%s, %02d-%s-%d %02d:%02d:%02d GMT":
0315                                          "%s, %02d-%s-%02d %02d:%02d:%02d GMT",
0316                        week[tm.ngx_tm_wday],
0317                        tm.ngx_tm_mday,
0318                        months[tm.ngx_tm_mon - 1],
0319                        (tm.ngx_tm_year > 2037) ? tm.ngx_tm_year:
0320                                                  tm.ngx_tm_year % 100,
0321                        tm.ngx_tm_hour,
0322                        tm.ngx_tm_min,
0323                        tm.ngx_tm_sec);
0324 }
0325 
0326 
0327 void
0328 ngx_gmtime(time_t t, ngx_tm_t *tp)
0329 {
0330     ngx_int_t   yday;
0331     ngx_uint_t  sec, min, hour, mday, mon, year, wday, days, leap;
0332 
0333     /* the calculation is valid for positive time_t only */
0334 
0335     if (t < 0) {
0336         t = 0;
0337     }
0338 
0339     days = t / 86400;
0340     sec = t % 86400;
0341 
0342     /*
0343      * no more than 4 year digits supported,
0344      * truncate to December 31, 9999, 23:59:59
0345      */
0346 
0347     if (days > 2932896) {
0348         days = 2932896;
0349         sec = 86399;
0350     }
0351 
0352     /* January 1, 1970 was Thursday */
0353 
0354     wday = (4 + days) % 7;
0355 
0356     hour = sec / 3600;
0357     sec %= 3600;
0358     min = sec / 60;
0359     sec %= 60;
0360 
0361     /*
0362      * the algorithm based on Gauss' formula,
0363      * see src/core/ngx_parse_time.c
0364      */
0365 
0366     /* days since March 1, 1 BC */
0367     days = days - (31 + 28) + 719527;
0368 
0369     /*
0370      * The "days" should be adjusted to 1 only, however, some March 1st's go
0371      * to previous year, so we adjust them to 2.  This causes also shift of the
0372      * last February days to next year, but we catch the case when "yday"
0373      * becomes negative.
0374      */
0375 
0376     year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1);
0377 
0378     yday = days - (365 * year + year / 4 - year / 100 + year / 400);
0379 
0380     if (yday < 0) {
0381         leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0));
0382         yday = 365 + leap + yday;
0383         year--;
0384     }
0385 
0386     /*
0387      * The empirical formula that maps "yday" to month.
0388      * There are at least 10 variants, some of them are:
0389      *     mon = (yday + 31) * 15 / 459
0390      *     mon = (yday + 31) * 17 / 520
0391      *     mon = (yday + 31) * 20 / 612
0392      */
0393 
0394     mon = (yday + 31) * 10 / 306;
0395 
0396     /* the Gauss' formula that evaluates days before the month */
0397 
0398     mday = yday - (367 * mon / 12 - 30) + 1;
0399 
0400     if (yday >= 306) {
0401 
0402         year++;
0403         mon -= 10;
0404 
0405         /*
0406          * there is no "yday" in Win32 SYSTEMTIME
0407          *
0408          * yday -= 306;
0409          */
0410 
0411     } else {
0412 
0413         mon += 2;
0414 
0415         /*
0416          * there is no "yday" in Win32 SYSTEMTIME
0417          *
0418          * yday += 31 + 28 + leap;
0419          */
0420     }
0421 
0422     tp->ngx_tm_sec = (ngx_tm_sec_t) sec;
0423     tp->ngx_tm_min = (ngx_tm_min_t) min;
0424     tp->ngx_tm_hour = (ngx_tm_hour_t) hour;
0425     tp->ngx_tm_mday = (ngx_tm_mday_t) mday;
0426     tp->ngx_tm_mon = (ngx_tm_mon_t) mon;
0427     tp->ngx_tm_year = (ngx_tm_year_t) year;
0428     tp->ngx_tm_wday = (ngx_tm_wday_t) wday;
0429 }
0430 
0431 
0432 time_t
0433 ngx_next_time(time_t when)
0434 {
0435     time_t     now, next;
0436     struct tm  tm;
0437 
0438     now = ngx_time();
0439 
0440     ngx_libc_localtime(now, &tm);
0441 
0442     tm.tm_hour = (int) (when / 3600);
0443     when %= 3600;
0444     tm.tm_min = (int) (when / 60);
0445     tm.tm_sec = (int) (when % 60);
0446 
0447     next = mktime(&tm);
0448 
0449     if (next == -1) {
0450         return -1;
0451     }
0452 
0453     if (next - now > 0) {
0454         return next;
0455     }
0456 
0457     tm.tm_mday++;
0458 
0459     /* mktime() should normalize a date (Jan 32, etc) */
0460 
0461     next = mktime(&tm);
0462 
0463     if (next != -1) {
0464         return next;
0465     }
0466 
0467     return -1;
0468 }