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>