Annotation of embedaddon/nginx/src/core/ngx_times.c, revision 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>