xref: /unit/src/nxt_thread_time.c (revision 223:bf98efe2c55c)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru 
90Sigor@sysoev.ru 
100Sigor@sysoev.ru /*
110Sigor@sysoev.ru  * Each thread keeps several time representations in its thread local
120Sigor@sysoev.ru  * storage:
130Sigor@sysoev.ru  *   the monotonic time in nanoseconds since unspecified point in the past,
140Sigor@sysoev.ru  *   the real time in seconds and nanoseconds since the Epoch,
150Sigor@sysoev.ru  *   the local time and GMT time structs,
160Sigor@sysoev.ru  *   and various user-defined text representations of local and GMT times.
170Sigor@sysoev.ru  *
180Sigor@sysoev.ru  * The monotonic time is used mainly by engine timers and is updated after
190Sigor@sysoev.ru  * a kernel operation which can block for unpredictable duration like event
200Sigor@sysoev.ru  * polling.  Besides getting the monotonic time is generally faster than
210Sigor@sysoev.ru  * getting the real time, so the monotonic time is also used for milestones
220Sigor@sysoev.ru  * to update cached real time seconds and, if debug log enabled, milliseconds.
230Sigor@sysoev.ru  * As a result, the cached real time is updated at most one time per second
240Sigor@sysoev.ru  * or millisecond respectively.  If there is a signal event support or in
250Sigor@sysoev.ru  * multi-threaded mode, then the cached real time and local time structs
260Sigor@sysoev.ru  * are updated only on demand.  In single-threaded mode without the signal
270Sigor@sysoev.ru  * event support the cached real and local time are updated synchronously
280Sigor@sysoev.ru  * with the monotonic time update.  GMT time structs and text representations
290Sigor@sysoev.ru  * are always updated only on demand.
300Sigor@sysoev.ru  */
310Sigor@sysoev.ru 
320Sigor@sysoev.ru 
330Sigor@sysoev.ru static void nxt_time_thread(void *data);
340Sigor@sysoev.ru static void nxt_thread_time_shared(nxt_monotonic_time_t *now);
350Sigor@sysoev.ru static void nxt_thread_realtime_update(nxt_thread_t *thr,
360Sigor@sysoev.ru     nxt_monotonic_time_t *now);
370Sigor@sysoev.ru static u_char *nxt_thread_time_string_no_cache(nxt_thread_t *thr,
380Sigor@sysoev.ru     nxt_time_string_t *ts, u_char *buf);
390Sigor@sysoev.ru static nxt_atomic_uint_t nxt_thread_time_string_slot(nxt_time_string_t *ts);
400Sigor@sysoev.ru static nxt_time_string_cache_t *nxt_thread_time_string_cache(nxt_thread_t *thr,
410Sigor@sysoev.ru     nxt_atomic_uint_t slot);
420Sigor@sysoev.ru 
430Sigor@sysoev.ru 
440Sigor@sysoev.ru static nxt_atomic_int_t               nxt_gmtoff;
45*223Sigor@sysoev.ru static nxt_bool_t                     nxt_use_shared_time = 0;
46*223Sigor@sysoev.ru static volatile nxt_monotonic_time_t  nxt_shared_time;
470Sigor@sysoev.ru 
480Sigor@sysoev.ru 
490Sigor@sysoev.ru void
nxt_thread_time_update(nxt_thread_t * thr)500Sigor@sysoev.ru nxt_thread_time_update(nxt_thread_t *thr)
510Sigor@sysoev.ru {
520Sigor@sysoev.ru     if (nxt_use_shared_time) {
530Sigor@sysoev.ru         nxt_thread_time_shared(&thr->time.now);
540Sigor@sysoev.ru 
550Sigor@sysoev.ru     } else {
560Sigor@sysoev.ru         nxt_monotonic_time(&thr->time.now);
570Sigor@sysoev.ru     }
580Sigor@sysoev.ru }
590Sigor@sysoev.ru 
600Sigor@sysoev.ru 
610Sigor@sysoev.ru void
nxt_thread_time_free(nxt_thread_t * thr)620Sigor@sysoev.ru nxt_thread_time_free(nxt_thread_t *thr)
630Sigor@sysoev.ru {
640Sigor@sysoev.ru     nxt_uint_t               i;
650Sigor@sysoev.ru     nxt_time_string_cache_t  *tsc;
660Sigor@sysoev.ru 
670Sigor@sysoev.ru     tsc = thr->time.strings;
680Sigor@sysoev.ru 
690Sigor@sysoev.ru     if (tsc) {
700Sigor@sysoev.ru         thr->time.no_cache = 1;
710Sigor@sysoev.ru 
720Sigor@sysoev.ru         for (i = 0; i < thr->time.nstrings; i++) {
7310Sigor@sysoev.ru             nxt_free(tsc[i].string.start);
740Sigor@sysoev.ru         }
750Sigor@sysoev.ru 
760Sigor@sysoev.ru         nxt_free(tsc);
770Sigor@sysoev.ru         thr->time.strings = NULL;
780Sigor@sysoev.ru     }
790Sigor@sysoev.ru }
800Sigor@sysoev.ru 
810Sigor@sysoev.ru 
820Sigor@sysoev.ru void
nxt_time_thread_start(nxt_msec_t interval)830Sigor@sysoev.ru nxt_time_thread_start(nxt_msec_t interval)
840Sigor@sysoev.ru {
850Sigor@sysoev.ru     nxt_thread_link_t    *link;
860Sigor@sysoev.ru     nxt_thread_handle_t  handle;
870Sigor@sysoev.ru 
880Sigor@sysoev.ru     link = nxt_zalloc(sizeof(nxt_thread_link_t));
890Sigor@sysoev.ru 
900Sigor@sysoev.ru     if (nxt_fast_path(link != NULL)) {
910Sigor@sysoev.ru         link->start = nxt_time_thread;
9253Sigor@sysoev.ru         link->work.data = (void *) (uintptr_t) interval;
930Sigor@sysoev.ru 
940Sigor@sysoev.ru         (void) nxt_thread_create(&handle, link);
950Sigor@sysoev.ru     }
960Sigor@sysoev.ru }
970Sigor@sysoev.ru 
980Sigor@sysoev.ru 
990Sigor@sysoev.ru static void
nxt_time_thread(void * data)1000Sigor@sysoev.ru nxt_time_thread(void *data)
1010Sigor@sysoev.ru {
1020Sigor@sysoev.ru     nxt_nsec_t            interval, rest;
1030Sigor@sysoev.ru     nxt_thread_t          *thr;
1040Sigor@sysoev.ru     nxt_monotonic_time_t  now;
1050Sigor@sysoev.ru 
1060Sigor@sysoev.ru     interval = (uintptr_t) data;
1070Sigor@sysoev.ru     interval *= 1000000;
1080Sigor@sysoev.ru 
1090Sigor@sysoev.ru     thr = nxt_thread();
1100Sigor@sysoev.ru     /*
1110Sigor@sysoev.ru      * The time thread is never preempted by asynchronous signals, since
1120Sigor@sysoev.ru      * the signals are processed synchronously by dedicated thread.
1130Sigor@sysoev.ru      */
1140Sigor@sysoev.ru     thr->time.signal = -1;
1150Sigor@sysoev.ru 
1160Sigor@sysoev.ru     nxt_log_debug(thr->log, "time thread");
1170Sigor@sysoev.ru 
1180Sigor@sysoev.ru     nxt_memzero(&now, sizeof(nxt_monotonic_time_t));
1190Sigor@sysoev.ru 
1200Sigor@sysoev.ru     nxt_monotonic_time(&now);
1210Sigor@sysoev.ru     nxt_thread_realtime_update(thr, &now);
1220Sigor@sysoev.ru 
1230Sigor@sysoev.ru     nxt_shared_time = now;
1240Sigor@sysoev.ru     nxt_use_shared_time = 1;
1250Sigor@sysoev.ru 
1260Sigor@sysoev.ru     for ( ;; ) {
1270Sigor@sysoev.ru         rest = 1000000000 - now.realtime.nsec;
1280Sigor@sysoev.ru 
1290Sigor@sysoev.ru         nxt_nanosleep(nxt_min(interval, rest));
1300Sigor@sysoev.ru 
1310Sigor@sysoev.ru         nxt_monotonic_time(&now);
1320Sigor@sysoev.ru         nxt_thread_realtime_update(thr, &now);
1330Sigor@sysoev.ru 
1340Sigor@sysoev.ru         nxt_shared_time = now;
1350Sigor@sysoev.ru 
1360Sigor@sysoev.ru #if 0
1370Sigor@sysoev.ru         thr->time.now = now;
1380Sigor@sysoev.ru         nxt_log_debug(thr->log, "time thread");
1390Sigor@sysoev.ru #endif
1400Sigor@sysoev.ru 
1410Sigor@sysoev.ru #if 0
1420Sigor@sysoev.ru         if (nxt_exiting) {
1430Sigor@sysoev.ru             nxt_use_shared_time = 0;
1440Sigor@sysoev.ru             return;
1450Sigor@sysoev.ru         }
1460Sigor@sysoev.ru #endif
1470Sigor@sysoev.ru     }
1480Sigor@sysoev.ru }
1490Sigor@sysoev.ru 
1500Sigor@sysoev.ru 
1510Sigor@sysoev.ru static void
nxt_thread_time_shared(nxt_monotonic_time_t * now)1520Sigor@sysoev.ru nxt_thread_time_shared(nxt_monotonic_time_t *now)
1530Sigor@sysoev.ru {
1540Sigor@sysoev.ru     nxt_uint_t  n;
1550Sigor@sysoev.ru     nxt_time_t  t;
1560Sigor@sysoev.ru     nxt_nsec_t  m, u;
1570Sigor@sysoev.ru 
1580Sigor@sysoev.ru     /* Lock-free thread time update. */
1590Sigor@sysoev.ru 
1600Sigor@sysoev.ru     for ( ;; ) {
1610Sigor@sysoev.ru         *now = nxt_shared_time;
1620Sigor@sysoev.ru 
1630Sigor@sysoev.ru         t = nxt_shared_time.realtime.sec;
1640Sigor@sysoev.ru         n = nxt_shared_time.realtime.nsec;
1650Sigor@sysoev.ru         m = nxt_shared_time.monotonic;
1660Sigor@sysoev.ru         u = nxt_shared_time.update;
1670Sigor@sysoev.ru 
1680Sigor@sysoev.ru         if (now->realtime.sec == t && now->realtime.nsec == n
1690Sigor@sysoev.ru             && now->monotonic == m && now->update == u)
1700Sigor@sysoev.ru         {
1710Sigor@sysoev.ru             return;
1720Sigor@sysoev.ru         }
1730Sigor@sysoev.ru     }
1740Sigor@sysoev.ru }
1750Sigor@sysoev.ru 
1760Sigor@sysoev.ru 
1770Sigor@sysoev.ru nxt_time_t
nxt_thread_time(nxt_thread_t * thr)1780Sigor@sysoev.ru nxt_thread_time(nxt_thread_t *thr)
1790Sigor@sysoev.ru {
1800Sigor@sysoev.ru     nxt_thread_realtime_update(thr, &thr->time.now);
1810Sigor@sysoev.ru 
1820Sigor@sysoev.ru     return thr->time.now.realtime.sec;
1830Sigor@sysoev.ru }
1840Sigor@sysoev.ru 
1850Sigor@sysoev.ru 
1860Sigor@sysoev.ru nxt_realtime_t *
nxt_thread_realtime(nxt_thread_t * thr)1870Sigor@sysoev.ru nxt_thread_realtime(nxt_thread_t *thr)
1880Sigor@sysoev.ru {
1890Sigor@sysoev.ru     nxt_thread_realtime_update(thr, &thr->time.now);
1900Sigor@sysoev.ru 
1910Sigor@sysoev.ru     return &thr->time.now.realtime;
1920Sigor@sysoev.ru }
1930Sigor@sysoev.ru 
1940Sigor@sysoev.ru 
1950Sigor@sysoev.ru static void
nxt_thread_realtime_update(nxt_thread_t * thr,nxt_monotonic_time_t * now)1960Sigor@sysoev.ru nxt_thread_realtime_update(nxt_thread_t *thr, nxt_monotonic_time_t *now)
1970Sigor@sysoev.ru {
1980Sigor@sysoev.ru     nxt_nsec_t  delta;
1990Sigor@sysoev.ru 
2000Sigor@sysoev.ru #if (NXT_DEBUG)
2010Sigor@sysoev.ru 
2020Sigor@sysoev.ru     if (nxt_slow_path(thr->log->level == NXT_LOG_DEBUG || nxt_debug)) {
2030Sigor@sysoev.ru 
2040Sigor@sysoev.ru         if (now->monotonic >= now->update) {
2050Sigor@sysoev.ru             nxt_realtime(&now->realtime);
2060Sigor@sysoev.ru 
2070Sigor@sysoev.ru             delta = 1000000 - now->realtime.nsec % 1000000;
2080Sigor@sysoev.ru             now->update = now->monotonic + delta;
2090Sigor@sysoev.ru         }
2100Sigor@sysoev.ru 
2110Sigor@sysoev.ru         return;
2120Sigor@sysoev.ru     }
2130Sigor@sysoev.ru 
2140Sigor@sysoev.ru #endif
2150Sigor@sysoev.ru 
2160Sigor@sysoev.ru     if (now->monotonic >= now->update) {
2170Sigor@sysoev.ru         nxt_realtime(&now->realtime);
2180Sigor@sysoev.ru 
2190Sigor@sysoev.ru         delta = 1000000000 - now->realtime.nsec;
2200Sigor@sysoev.ru         now->update = now->monotonic + delta;
2210Sigor@sysoev.ru     }
2220Sigor@sysoev.ru }
2230Sigor@sysoev.ru 
2240Sigor@sysoev.ru 
2250Sigor@sysoev.ru u_char *
nxt_thread_time_string(nxt_thread_t * thr,nxt_time_string_t * ts,u_char * buf)2260Sigor@sysoev.ru nxt_thread_time_string(nxt_thread_t *thr, nxt_time_string_t *ts, u_char *buf)
2270Sigor@sysoev.ru {
2280Sigor@sysoev.ru     u_char                   *p;
2290Sigor@sysoev.ru     struct tm                *tm;
2300Sigor@sysoev.ru     nxt_time_t               s;
2310Sigor@sysoev.ru     nxt_bool_t               update;
2320Sigor@sysoev.ru     nxt_atomic_uint_t        slot;
2330Sigor@sysoev.ru     nxt_time_string_cache_t  *tsc;
2340Sigor@sysoev.ru 
2350Sigor@sysoev.ru     if (nxt_slow_path(thr == NULL || thr->time.no_cache)) {
2360Sigor@sysoev.ru         return nxt_thread_time_string_no_cache(thr, ts, buf);
2370Sigor@sysoev.ru     }
2380Sigor@sysoev.ru 
2390Sigor@sysoev.ru     slot = nxt_thread_time_string_slot(ts);
2400Sigor@sysoev.ru 
2410Sigor@sysoev.ru     tsc = nxt_thread_time_string_cache(thr, slot);
2420Sigor@sysoev.ru     if (tsc == NULL) {
2430Sigor@sysoev.ru         return buf;
2440Sigor@sysoev.ru     }
2450Sigor@sysoev.ru 
2460Sigor@sysoev.ru     if (thr->time.signal < 0) {
2470Sigor@sysoev.ru         /*
2480Sigor@sysoev.ru          * Lazy real time update:
2490Sigor@sysoev.ru          * signal event support or multi-threaded mode.
2500Sigor@sysoev.ru          */
2510Sigor@sysoev.ru         nxt_thread_realtime_update(thr, &thr->time.now);
2520Sigor@sysoev.ru     }
2530Sigor@sysoev.ru 
2540Sigor@sysoev.ru     s = thr->time.now.realtime.sec;
2550Sigor@sysoev.ru 
2560Sigor@sysoev.ru     update = (s != tsc->last);
2570Sigor@sysoev.ru 
2580Sigor@sysoev.ru #if (NXT_DEBUG)
2590Sigor@sysoev.ru 
2600Sigor@sysoev.ru     if (ts->msec == NXT_THREAD_TIME_MSEC
2610Sigor@sysoev.ru         && (nxt_slow_path(thr->log->level == NXT_LOG_DEBUG || nxt_debug)))
2620Sigor@sysoev.ru     {
2630Sigor@sysoev.ru         nxt_msec_t  ms;
2640Sigor@sysoev.ru 
2650Sigor@sysoev.ru         ms = thr->time.now.realtime.nsec / 1000000;
2660Sigor@sysoev.ru         update |= (ms != tsc->last_msec);
2670Sigor@sysoev.ru         tsc->last_msec = ms;
2680Sigor@sysoev.ru     }
2690Sigor@sysoev.ru 
2700Sigor@sysoev.ru #endif
2710Sigor@sysoev.ru 
2720Sigor@sysoev.ru     if (nxt_slow_path(update)) {
2730Sigor@sysoev.ru 
2740Sigor@sysoev.ru         if (ts->timezone == NXT_THREAD_TIME_LOCAL) {
2750Sigor@sysoev.ru 
2760Sigor@sysoev.ru             tm = &thr->time.localtime;
2770Sigor@sysoev.ru 
2780Sigor@sysoev.ru             if (nxt_slow_path(s != thr->time.last_localtime)) {
2790Sigor@sysoev.ru 
2800Sigor@sysoev.ru                 if (thr->time.signal < 0) {
2810Sigor@sysoev.ru                     /*
2820Sigor@sysoev.ru                      * Lazy local time update:
2830Sigor@sysoev.ru                      * signal event support or multi-threaded mode.
2840Sigor@sysoev.ru                      */
2850Sigor@sysoev.ru                     nxt_localtime(s, &thr->time.localtime);
2860Sigor@sysoev.ru                     thr->time.last_localtime = s;
2870Sigor@sysoev.ru 
2880Sigor@sysoev.ru                 } else {
2890Sigor@sysoev.ru                     /*
2900Sigor@sysoev.ru                      * "thr->time.signal >= 0" means that a thread may be
2910Sigor@sysoev.ru                      * interrupted by a signal handler.  Since localtime()
2920Sigor@sysoev.ru                      * cannot be safely called in a signal context, the
2930Sigor@sysoev.ru                      * thread's thr->time.localtime must be updated regularly
2940Sigor@sysoev.ru                      * by nxt_thread_time_update() in non-signal context.
2950Sigor@sysoev.ru                      * Stale timestamp means that nxt_thread_time_string()
2960Sigor@sysoev.ru                      * is being called in a signal context, so here is
2970Sigor@sysoev.ru                      * Async-Signal-Safe localtime() emulation using the
2980Sigor@sysoev.ru                      * latest cached GMT offset.
2990Sigor@sysoev.ru                      *
3000Sigor@sysoev.ru                      * The timestamp is not set here intentionally to update
3010Sigor@sysoev.ru                      * thr->time.localtime later in non-signal context.  The
3020Sigor@sysoev.ru                      * real previously cached thr->localtime is used because
3030Sigor@sysoev.ru                      * Linux and Solaris strftime() depend on tm.tm_isdst
3040Sigor@sysoev.ru                      * and tm.tm_gmtoff fields.
3050Sigor@sysoev.ru                      */
3060Sigor@sysoev.ru                     nxt_gmtime(s + nxt_timezone(tm), tm);
3070Sigor@sysoev.ru                 }
3080Sigor@sysoev.ru             }
3090Sigor@sysoev.ru 
3100Sigor@sysoev.ru         } else {
3110Sigor@sysoev.ru             tm = &thr->time.gmtime;
3120Sigor@sysoev.ru 
3130Sigor@sysoev.ru             if (nxt_slow_path(s != thr->time.last_gmtime)) {
3140Sigor@sysoev.ru                 nxt_gmtime(s, tm);
3150Sigor@sysoev.ru                 thr->time.last_gmtime = s;
3160Sigor@sysoev.ru             }
3170Sigor@sysoev.ru 
3180Sigor@sysoev.ru         }
3190Sigor@sysoev.ru 
32010Sigor@sysoev.ru         p = tsc->string.start;
3210Sigor@sysoev.ru 
3220Sigor@sysoev.ru         if (nxt_slow_path(p == NULL)) {
3230Sigor@sysoev.ru 
3240Sigor@sysoev.ru             thr->time.no_cache = 1;
3250Sigor@sysoev.ru             p = nxt_zalloc(ts->size);
3260Sigor@sysoev.ru             thr->time.no_cache = 0;
3270Sigor@sysoev.ru 
3280Sigor@sysoev.ru             if (p == NULL) {
3290Sigor@sysoev.ru                 return buf;
3300Sigor@sysoev.ru             }
3310Sigor@sysoev.ru 
33210Sigor@sysoev.ru             tsc->string.start = p;
3330Sigor@sysoev.ru         }
3340Sigor@sysoev.ru 
3350Sigor@sysoev.ru         p = ts->handler(p, &thr->time.now.realtime, tm, ts->size, ts->format);
3360Sigor@sysoev.ru 
33710Sigor@sysoev.ru         tsc->string.length = p - tsc->string.start;
3380Sigor@sysoev.ru 
33910Sigor@sysoev.ru         if (nxt_slow_path(tsc->string.length == 0)) {
3400Sigor@sysoev.ru             return buf;
3410Sigor@sysoev.ru         }
3420Sigor@sysoev.ru 
3430Sigor@sysoev.ru         tsc->last = s;
3440Sigor@sysoev.ru     }
3450Sigor@sysoev.ru 
34610Sigor@sysoev.ru     return nxt_cpymem(buf, tsc->string.start, tsc->string.length);
3470Sigor@sysoev.ru }
3480Sigor@sysoev.ru 
3490Sigor@sysoev.ru 
3500Sigor@sysoev.ru static u_char *
nxt_thread_time_string_no_cache(nxt_thread_t * thr,nxt_time_string_t * ts,u_char * buf)3510Sigor@sysoev.ru nxt_thread_time_string_no_cache(nxt_thread_t *thr, nxt_time_string_t *ts,
3520Sigor@sysoev.ru     u_char *buf)
3530Sigor@sysoev.ru {
3540Sigor@sysoev.ru     struct tm       tm;
3550Sigor@sysoev.ru     nxt_realtime_t  now;
3560Sigor@sysoev.ru 
3570Sigor@sysoev.ru     nxt_realtime(&now);
3580Sigor@sysoev.ru 
3590Sigor@sysoev.ru     if (ts->timezone == NXT_THREAD_TIME_LOCAL) {
3600Sigor@sysoev.ru 
3610Sigor@sysoev.ru         if (thr == NULL || thr->time.signal <= 0) {
3620Sigor@sysoev.ru             /* Non-signal context */
3630Sigor@sysoev.ru             nxt_localtime(now.sec, &tm);
3640Sigor@sysoev.ru 
3650Sigor@sysoev.ru         } else {
3660Sigor@sysoev.ru             nxt_gmtime(now.sec + nxt_gmtoff, &tm);
3670Sigor@sysoev.ru         }
3680Sigor@sysoev.ru 
3690Sigor@sysoev.ru     } else {
3700Sigor@sysoev.ru         nxt_gmtime(now.sec, &tm);
3710Sigor@sysoev.ru     }
3720Sigor@sysoev.ru 
3730Sigor@sysoev.ru     return ts->handler(buf, &now, &tm, ts->size, ts->format);
3740Sigor@sysoev.ru }
3750Sigor@sysoev.ru 
3760Sigor@sysoev.ru 
3770Sigor@sysoev.ru static nxt_atomic_uint_t
nxt_thread_time_string_slot(nxt_time_string_t * ts)3780Sigor@sysoev.ru nxt_thread_time_string_slot(nxt_time_string_t *ts)
3790Sigor@sysoev.ru {
3800Sigor@sysoev.ru     static nxt_atomic_t  slot;
3810Sigor@sysoev.ru 
3820Sigor@sysoev.ru     while (nxt_slow_path((nxt_atomic_int_t) ts->slot < 0)) {
3830Sigor@sysoev.ru         /*
3840Sigor@sysoev.ru          * Atomic allocation of a slot number.
3850Sigor@sysoev.ru          * -1 means an uninitialized slot,
3860Sigor@sysoev.ru          * -2 is the initializing lock to assure the single value for the slot.
3870Sigor@sysoev.ru          */
3880Sigor@sysoev.ru         if (nxt_atomic_cmp_set(&ts->slot, -1, -2)) {
3890Sigor@sysoev.ru             ts->slot = nxt_atomic_fetch_add(&slot, 1);
3900Sigor@sysoev.ru 
3910Sigor@sysoev.ru             /* No "break" here since it adds only dispensable "jmp". */
3920Sigor@sysoev.ru         }
3930Sigor@sysoev.ru     }
3940Sigor@sysoev.ru 
3950Sigor@sysoev.ru     return (nxt_atomic_uint_t) ts->slot;
3960Sigor@sysoev.ru }
3970Sigor@sysoev.ru 
3980Sigor@sysoev.ru 
3990Sigor@sysoev.ru static nxt_time_string_cache_t *
nxt_thread_time_string_cache(nxt_thread_t * thr,nxt_atomic_uint_t slot)4000Sigor@sysoev.ru nxt_thread_time_string_cache(nxt_thread_t *thr, nxt_atomic_uint_t slot)
4010Sigor@sysoev.ru {
4020Sigor@sysoev.ru     size_t                   size;
4030Sigor@sysoev.ru     nxt_atomic_uint_t        i, nstrings;
4040Sigor@sysoev.ru     nxt_time_string_cache_t  *tsc;
4050Sigor@sysoev.ru 
4060Sigor@sysoev.ru     if (nxt_fast_path(slot < thr->time.nstrings)) {
4070Sigor@sysoev.ru         tsc = &thr->time.strings[slot];
40810Sigor@sysoev.ru         nxt_prefetch(tsc->string.start);
4090Sigor@sysoev.ru         return tsc;
4100Sigor@sysoev.ru     }
4110Sigor@sysoev.ru 
4120Sigor@sysoev.ru     nstrings = slot + 1;
4130Sigor@sysoev.ru     size = nstrings * sizeof(nxt_time_string_cache_t);
4140Sigor@sysoev.ru 
4150Sigor@sysoev.ru     thr->time.no_cache = 1;
4160Sigor@sysoev.ru     tsc = nxt_realloc(thr->time.strings, size);
4170Sigor@sysoev.ru     thr->time.no_cache = 0;
4180Sigor@sysoev.ru 
4190Sigor@sysoev.ru     if (tsc == NULL) {
4200Sigor@sysoev.ru         return NULL;
4210Sigor@sysoev.ru     }
4220Sigor@sysoev.ru 
4230Sigor@sysoev.ru     for (i = thr->time.nstrings; i < nstrings; i++) {
4240Sigor@sysoev.ru         tsc[i].last = -1;
42510Sigor@sysoev.ru         tsc[i].string.start = NULL;
4260Sigor@sysoev.ru     }
4270Sigor@sysoev.ru 
4280Sigor@sysoev.ru     thr->time.strings = tsc;
4290Sigor@sysoev.ru     thr->time.nstrings = nstrings;
4300Sigor@sysoev.ru 
4310Sigor@sysoev.ru     return &tsc[slot];
4320Sigor@sysoev.ru }
433