Annotation of embedaddon/nginx/src/core/ngx_times.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: 
                     11: 
                     12: /*
                     13:  * The time may be updated by signal handler or by several threads.
                     14:  * The time update operations are rare and require to hold the ngx_time_lock.
                     15:  * The time read operations are frequent, so they are lock-free and get time
                     16:  * values and strings from the current slot.  Thus thread may get the corrupted
                     17:  * values only if it is preempted while copying and then it is not scheduled
                     18:  * to run more than NGX_TIME_SLOTS seconds.
                     19:  */
                     20: 
                     21: #define NGX_TIME_SLOTS   64
                     22: 
                     23: static ngx_uint_t        slot;
                     24: static ngx_atomic_t      ngx_time_lock;
                     25: 
                     26: volatile ngx_msec_t      ngx_current_msec;
                     27: volatile ngx_time_t     *ngx_cached_time;
                     28: volatile ngx_str_t       ngx_cached_err_log_time;
                     29: volatile ngx_str_t       ngx_cached_http_time;
                     30: volatile ngx_str_t       ngx_cached_http_log_time;
                     31: volatile ngx_str_t       ngx_cached_http_log_iso8601;
                     32: 
                     33: #if !(NGX_WIN32)
                     34: 
                     35: /*
                     36:  * localtime() and localtime_r() are not Async-Signal-Safe functions, therefore,
                     37:  * they must not be called by a signal handler, so we use the cached
                     38:  * GMT offset value. Fortunately the value is changed only two times a year.
                     39:  */
                     40: 
                     41: static ngx_int_t         cached_gmtoff;
                     42: #endif
                     43: 
                     44: static ngx_time_t        cached_time[NGX_TIME_SLOTS];
                     45: static u_char            cached_err_log_time[NGX_TIME_SLOTS]
                     46:                                     [sizeof("1970/09/28 12:00:00")];
                     47: static u_char            cached_http_time[NGX_TIME_SLOTS]
                     48:                                     [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
                     49: static u_char            cached_http_log_time[NGX_TIME_SLOTS]
                     50:                                     [sizeof("28/Sep/1970:12:00:00 +0600")];
                     51: static u_char            cached_http_log_iso8601[NGX_TIME_SLOTS]
                     52:                                     [sizeof("1970-09-28T12:00:00+06:00")];
                     53: 
                     54: 
                     55: static char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
                     56: static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                     57:                            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
                     58: 
                     59: void
                     60: ngx_time_init(void)
                     61: {
                     62:     ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
                     63:     ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
                     64:     ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
                     65:     ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
                     66: 
                     67:     ngx_cached_time = &cached_time[0];
                     68: 
                     69:     ngx_time_update();
                     70: }
                     71: 
                     72: 
                     73: void
                     74: ngx_time_update(void)
                     75: {
                     76:     u_char          *p0, *p1, *p2, *p3;
                     77:     ngx_tm_t         tm, gmt;
                     78:     time_t           sec;
                     79:     ngx_uint_t       msec;
                     80:     ngx_time_t      *tp;
                     81:     struct timeval   tv;
                     82: 
                     83:     if (!ngx_trylock(&ngx_time_lock)) {
                     84:         return;
                     85:     }
                     86: 
                     87:     ngx_gettimeofday(&tv);
                     88: 
                     89:     sec = tv.tv_sec;
                     90:     msec = tv.tv_usec / 1000;
                     91: 
                     92:     ngx_current_msec = (ngx_msec_t) sec * 1000 + msec;
                     93: 
                     94:     tp = &cached_time[slot];
                     95: 
                     96:     if (tp->sec == sec) {
                     97:         tp->msec = msec;
                     98:         ngx_unlock(&ngx_time_lock);
                     99:         return;
                    100:     }
                    101: 
                    102:     if (slot == NGX_TIME_SLOTS - 1) {
                    103:         slot = 0;
                    104:     } else {
                    105:         slot++;
                    106:     }
                    107: 
                    108:     tp = &cached_time[slot];
                    109: 
                    110:     tp->sec = sec;
                    111:     tp->msec = msec;
                    112: 
                    113:     ngx_gmtime(sec, &gmt);
                    114: 
                    115: 
                    116:     p0 = &cached_http_time[slot][0];
                    117: 
                    118:     (void) ngx_sprintf(p0, "%s, %02d %s %4d %02d:%02d:%02d GMT",
                    119:                        week[gmt.ngx_tm_wday], gmt.ngx_tm_mday,
                    120:                        months[gmt.ngx_tm_mon - 1], gmt.ngx_tm_year,
                    121:                        gmt.ngx_tm_hour, gmt.ngx_tm_min, gmt.ngx_tm_sec);
                    122: 
                    123: #if (NGX_HAVE_GETTIMEZONE)
                    124: 
                    125:     tp->gmtoff = ngx_gettimezone();
                    126:     ngx_gmtime(sec + tp->gmtoff * 60, &tm);
                    127: 
                    128: #elif (NGX_HAVE_GMTOFF)
                    129: 
                    130:     ngx_localtime(sec, &tm);
                    131:     cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
                    132:     tp->gmtoff = cached_gmtoff;
                    133: 
                    134: #else
                    135: 
                    136:     ngx_localtime(sec, &tm);
                    137:     cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst);
                    138:     tp->gmtoff = cached_gmtoff;
                    139: 
                    140: #endif
                    141: 
                    142: 
                    143:     p1 = &cached_err_log_time[slot][0];
                    144: 
                    145:     (void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d",
                    146:                        tm.ngx_tm_year, tm.ngx_tm_mon,
                    147:                        tm.ngx_tm_mday, tm.ngx_tm_hour,
                    148:                        tm.ngx_tm_min, tm.ngx_tm_sec);
                    149: 
                    150: 
                    151:     p2 = &cached_http_log_time[slot][0];
                    152: 
                    153:     (void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d",
                    154:                        tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
                    155:                        tm.ngx_tm_year, tm.ngx_tm_hour,
                    156:                        tm.ngx_tm_min, tm.ngx_tm_sec,
                    157:                        tp->gmtoff < 0 ? '-' : '+',
                    158:                        ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
                    159: 
                    160:     p3 = &cached_http_log_iso8601[slot][0];
                    161: 
                    162:     (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
                    163:                        tm.ngx_tm_year, tm.ngx_tm_mon,
                    164:                        tm.ngx_tm_mday, tm.ngx_tm_hour,
                    165:                        tm.ngx_tm_min, tm.ngx_tm_sec,
                    166:                        tp->gmtoff < 0 ? '-' : '+',
                    167:                        ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
                    168: 
                    169: 
                    170:     ngx_memory_barrier();
                    171: 
                    172:     ngx_cached_time = tp;
                    173:     ngx_cached_http_time.data = p0;
                    174:     ngx_cached_err_log_time.data = p1;
                    175:     ngx_cached_http_log_time.data = p2;
                    176:     ngx_cached_http_log_iso8601.data = p3;
                    177: 
                    178:     ngx_unlock(&ngx_time_lock);
                    179: }
                    180: 
                    181: 
                    182: #if !(NGX_WIN32)
                    183: 
                    184: void
                    185: ngx_time_sigsafe_update(void)
                    186: {
                    187:     u_char          *p;
                    188:     ngx_tm_t         tm;
                    189:     time_t           sec;
                    190:     ngx_time_t      *tp;
                    191:     struct timeval   tv;
                    192: 
                    193:     if (!ngx_trylock(&ngx_time_lock)) {
                    194:         return;
                    195:     }
                    196: 
                    197:     ngx_gettimeofday(&tv);
                    198: 
                    199:     sec = tv.tv_sec;
                    200: 
                    201:     tp = &cached_time[slot];
                    202: 
                    203:     if (tp->sec == sec) {
                    204:         ngx_unlock(&ngx_time_lock);
                    205:         return;
                    206:     }
                    207: 
                    208:     if (slot == NGX_TIME_SLOTS - 1) {
                    209:         slot = 0;
                    210:     } else {
                    211:         slot++;
                    212:     }
                    213: 
                    214:     tp = &cached_time[slot];
                    215: 
                    216:     tp->sec = 0;
                    217: 
                    218:     ngx_gmtime(sec + cached_gmtoff * 60, &tm);
                    219: 
                    220:     p = &cached_err_log_time[slot][0];
                    221: 
                    222:     (void) ngx_sprintf(p, "%4d/%02d/%02d %02d:%02d:%02d",
                    223:                        tm.ngx_tm_year, tm.ngx_tm_mon,
                    224:                        tm.ngx_tm_mday, tm.ngx_tm_hour,
                    225:                        tm.ngx_tm_min, tm.ngx_tm_sec);
                    226: 
                    227:     ngx_memory_barrier();
                    228: 
                    229:     ngx_cached_err_log_time.data = p;
                    230: 
                    231:     ngx_unlock(&ngx_time_lock);
                    232: }
                    233: 
                    234: #endif
                    235: 
                    236: 
                    237: u_char *
                    238: ngx_http_time(u_char *buf, time_t t)
                    239: {
                    240:     ngx_tm_t  tm;
                    241: 
                    242:     ngx_gmtime(t, &tm);
                    243: 
                    244:     return ngx_sprintf(buf, "%s, %02d %s %4d %02d:%02d:%02d GMT",
                    245:                        week[tm.ngx_tm_wday],
                    246:                        tm.ngx_tm_mday,
                    247:                        months[tm.ngx_tm_mon - 1],
                    248:                        tm.ngx_tm_year,
                    249:                        tm.ngx_tm_hour,
                    250:                        tm.ngx_tm_min,
                    251:                        tm.ngx_tm_sec);
                    252: }
                    253: 
                    254: 
                    255: u_char *
                    256: ngx_http_cookie_time(u_char *buf, time_t t)
                    257: {
                    258:     ngx_tm_t  tm;
                    259: 
                    260:     ngx_gmtime(t, &tm);
                    261: 
                    262:     /*
                    263:      * Netscape 3.x does not understand 4-digit years at all and
                    264:      * 2-digit years more than "37"
                    265:      */
                    266: 
                    267:     return ngx_sprintf(buf,
                    268:                        (tm.ngx_tm_year > 2037) ?
                    269:                                          "%s, %02d-%s-%d %02d:%02d:%02d GMT":
                    270:                                          "%s, %02d-%s-%02d %02d:%02d:%02d GMT",
                    271:                        week[tm.ngx_tm_wday],
                    272:                        tm.ngx_tm_mday,
                    273:                        months[tm.ngx_tm_mon - 1],
                    274:                        (tm.ngx_tm_year > 2037) ? tm.ngx_tm_year:
                    275:                                                  tm.ngx_tm_year % 100,
                    276:                        tm.ngx_tm_hour,
                    277:                        tm.ngx_tm_min,
                    278:                        tm.ngx_tm_sec);
                    279: }
                    280: 
                    281: 
                    282: void
                    283: ngx_gmtime(time_t t, ngx_tm_t *tp)
                    284: {
                    285:     ngx_int_t   yday;
                    286:     ngx_uint_t  n, sec, min, hour, mday, mon, year, wday, days, leap;
                    287: 
                    288:     /* the calculation is valid for positive time_t only */
                    289: 
                    290:     n = (ngx_uint_t) t;
                    291: 
                    292:     days = n / 86400;
                    293: 
                    294:     /* January 1, 1970 was Thursday */
                    295: 
                    296:     wday = (4 + days) % 7;
                    297: 
                    298:     n %= 86400;
                    299:     hour = n / 3600;
                    300:     n %= 3600;
                    301:     min = n / 60;
                    302:     sec = n % 60;
                    303: 
                    304:     /*
                    305:      * the algorithm based on Gauss' formula,
                    306:      * see src/http/ngx_http_parse_time.c
                    307:      */
                    308: 
                    309:     /* days since March 1, 1 BC */
                    310:     days = days - (31 + 28) + 719527;
                    311: 
                    312:     /*
                    313:      * The "days" should be adjusted to 1 only, however, some March 1st's go
                    314:      * to previous year, so we adjust them to 2.  This causes also shift of the
                    315:      * last February days to next year, but we catch the case when "yday"
                    316:      * becomes negative.
                    317:      */
                    318: 
                    319:     year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1);
                    320: 
                    321:     yday = days - (365 * year + year / 4 - year / 100 + year / 400);
                    322: 
                    323:     if (yday < 0) {
                    324:         leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0));
                    325:         yday = 365 + leap + yday;
                    326:         year--;
                    327:     }
                    328: 
                    329:     /*
                    330:      * The empirical formula that maps "yday" to month.
                    331:      * There are at least 10 variants, some of them are:
                    332:      *     mon = (yday + 31) * 15 / 459
                    333:      *     mon = (yday + 31) * 17 / 520
                    334:      *     mon = (yday + 31) * 20 / 612
                    335:      */
                    336: 
                    337:     mon = (yday + 31) * 10 / 306;
                    338: 
                    339:     /* the Gauss' formula that evaluates days before the month */
                    340: 
                    341:     mday = yday - (367 * mon / 12 - 30) + 1;
                    342: 
                    343:     if (yday >= 306) {
                    344: 
                    345:         year++;
                    346:         mon -= 10;
                    347: 
                    348:         /*
                    349:          * there is no "yday" in Win32 SYSTEMTIME
                    350:          *
                    351:          * yday -= 306;
                    352:          */
                    353: 
                    354:     } else {
                    355: 
                    356:         mon += 2;
                    357: 
                    358:         /*
                    359:          * there is no "yday" in Win32 SYSTEMTIME
                    360:          *
                    361:          * yday += 31 + 28 + leap;
                    362:          */
                    363:     }
                    364: 
                    365:     tp->ngx_tm_sec = (ngx_tm_sec_t) sec;
                    366:     tp->ngx_tm_min = (ngx_tm_min_t) min;
                    367:     tp->ngx_tm_hour = (ngx_tm_hour_t) hour;
                    368:     tp->ngx_tm_mday = (ngx_tm_mday_t) mday;
                    369:     tp->ngx_tm_mon = (ngx_tm_mon_t) mon;
                    370:     tp->ngx_tm_year = (ngx_tm_year_t) year;
                    371:     tp->ngx_tm_wday = (ngx_tm_wday_t) wday;
                    372: }
                    373: 
                    374: 
                    375: time_t
                    376: ngx_next_time(time_t when)
                    377: {
                    378:     time_t     now, next;
                    379:     struct tm  tm;
                    380: 
                    381:     now = ngx_time();
                    382: 
                    383:     ngx_libc_localtime(now, &tm);
                    384: 
                    385:     tm.tm_hour = (int) (when / 3600);
                    386:     when %= 3600;
                    387:     tm.tm_min = (int) (when / 60);
                    388:     tm.tm_sec = (int) (when % 60);
                    389: 
                    390:     next = mktime(&tm);
                    391: 
                    392:     if (next == -1) {
                    393:         return -1;
                    394:     }
                    395: 
                    396:     if (next - now > 0) {
                    397:         return next;
                    398:     }
                    399: 
                    400:     tm.tm_mday++;
                    401: 
                    402:     /* mktime() should normalize a date (Jan 32, etc) */
                    403: 
                    404:     next = mktime(&tm);
                    405: 
                    406:     if (next != -1) {
                    407:         return next;
                    408:     }
                    409: 
                    410:     return -1;
                    411: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>