# HG changeset patch # User Igor Sysoev # Date 1275906908 0 # Node ID e1409e56ba7c2639930f3eaa7721d4d4ab43b826 # Parent 2d21e02fc01dcc181680daf9af7ec5f9a4746d75 merge r3473, r3474, r3385, r3386, r3537: signal processing stability: *) use sys_errlist[] in signal handler instead of non Async-Signal-Safe strerror_r() *) do not update time in the timer signal handler, since localtime_r() is not Async-Signal-Safe function *) use previously cached GMT offset value to update time from a signal handler *) change ngx_time_update() interface since there are no notification methods those return time *) introduce ngx_time_sigsafe_update() to update the error log time only *) change ngx_time_update() interface diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -133,6 +133,16 @@ ngx_feature_test="char buf[1024]; long n . auto/feature +ngx_feature="sys_errlist[]" +ngx_feature_name="NGX_HAVE_SYS_ERRLIST" +ngx_feature_run=yes +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="int n = sys_nerr; const char *p = sys_errlist[1];" +. auto/feature + + ngx_feature="localtime_r()" ngx_feature_name="NGX_HAVE_LOCALTIME_R" ngx_feature_run=no diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -63,7 +63,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) tp = ngx_timeofday(); tp->sec = 0; - ngx_time_update(0, 0); + ngx_time_update(); log = old_cycle->log; diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -28,6 +28,17 @@ volatile ngx_str_t ngx_cached_err_ volatile ngx_str_t ngx_cached_http_time; volatile ngx_str_t ngx_cached_http_log_time; +#if !(NGX_WIN32) + +/* + * locatime() and localtime_r() are not Async-Signal-Safe functions, therefore, + * they must not be called by a signal handler, so we use the cached + * GMT offset value. Fortunately the value is changed only two times a year. + */ + +static ngx_int_t cached_gmtoff; +#endif + static ngx_time_t cached_time[NGX_TIME_SLOTS]; static u_char cached_err_log_time[NGX_TIME_SLOTS] [sizeof("1970/09/28 12:00:00")]; @@ -50,15 +61,17 @@ ngx_time_init(void) ngx_cached_time = &cached_time[0]; - ngx_time_update(0, 0); + ngx_time_update(); } void -ngx_time_update(time_t sec, ngx_uint_t msec) +ngx_time_update(void) { u_char *p0, *p1, *p2; ngx_tm_t tm, gmt; + time_t sec; + ngx_uint_t msec; ngx_time_t *tp; struct timeval tv; @@ -66,12 +79,10 @@ ngx_time_update(time_t sec, ngx_uint_t m return; } - if (sec == 0) { - ngx_gettimeofday(&tv); + ngx_gettimeofday(&tv); - sec = tv.tv_sec; - msec = tv.tv_usec / 1000; - } + sec = tv.tv_sec; + msec = tv.tv_usec / 1000; ngx_current_msec = (ngx_msec_t) sec * 1000 + msec; @@ -112,12 +123,14 @@ ngx_time_update(time_t sec, ngx_uint_t m #elif (NGX_HAVE_GMTOFF) ngx_localtime(sec, &tm); - tp->gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60); + cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60); + tp->gmtoff = cached_gmtoff; #else ngx_localtime(sec, &tm); - tp->gmtoff = ngx_timezone(tm.ngx_tm_isdst); + cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst); + tp->gmtoff = cached_gmtoff; #endif @@ -151,6 +164,57 @@ ngx_time_update(time_t sec, ngx_uint_t m } +#if !(NGX_WIN32) + +void +ngx_time_sigsafe_update(void) +{ + u_char *p; + ngx_tm_t tm; + time_t sec; + ngx_time_t *tp; + struct timeval tv; + + if (!ngx_trylock(&ngx_time_lock)) { + return; + } + + ngx_gettimeofday(&tv); + + sec = tv.tv_sec; + + tp = &cached_time[slot]; + + if (tp->sec == sec) { + ngx_unlock(&ngx_time_lock); + return; + } + + if (slot == NGX_TIME_SLOTS - 1) { + slot = 0; + } else { + slot++; + } + + ngx_gmtime(sec + cached_gmtoff * 60, &tm); + + p = &cached_err_log_time[slot][0]; + + (void) ngx_sprintf(p, "%4d/%02d/%02d %02d:%02d:%02d", + tm.ngx_tm_year, tm.ngx_tm_mon, + tm.ngx_tm_mday, tm.ngx_tm_hour, + tm.ngx_tm_min, tm.ngx_tm_sec); + + ngx_memory_barrier(); + + ngx_cached_err_log_time.data = p; + + ngx_unlock(&ngx_time_lock); +} + +#endif + + u_char * ngx_http_time(u_char *buf, time_t t) { diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h --- a/src/core/ngx_times.h +++ b/src/core/ngx_times.h @@ -20,7 +20,8 @@ typedef struct { void ngx_time_init(void); -void ngx_time_update(time_t sec, ngx_uint_t msec); +void ngx_time_update(void); +void ngx_time_sigsafe_update(void); u_char *ngx_http_time(u_char *buf, time_t t); u_char *ngx_http_cookie_time(u_char *buf, time_t t); void ngx_gmtime(time_t t, ngx_tm_t *tp); diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -375,8 +375,8 @@ ngx_devpoll_process_events(ngx_cycle_t * err = 0; } - if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { + ngx_time_update(); } if (err) { diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -407,8 +407,8 @@ ngx_epoll_process_events(ngx_cycle_t *cy err = 0; } - if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { + ngx_time_update(); } if (err) { diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -405,7 +405,7 @@ ngx_eventport_process_events(ngx_cycle_t err = ngx_errno; if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + ngx_time_update(); } if (n == -1) { @@ -439,7 +439,7 @@ ngx_eventport_process_events(ngx_cycle_t for (i = 0; i < events; i++) { if (event_list[i].portev_source == PORT_SOURCE_TIMER) { - ngx_time_update(0, 0); + ngx_time_update(); continue; } diff --git a/src/event/modules/ngx_iocp_module.c b/src/event/modules/ngx_iocp_module.c --- a/src/event/modules/ngx_iocp_module.c +++ b/src/event/modules/ngx_iocp_module.c @@ -163,7 +163,7 @@ ngx_iocp_timer(void *data) for ( ;; ) { Sleep(timer); - ngx_time_update(0, 0); + ngx_time_update(); #if 1 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer"); #endif @@ -258,7 +258,7 @@ ngx_int_t ngx_iocp_process_events(ngx_cy delta = ngx_current_msec; if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + ngx_time_update(); } ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -543,8 +543,8 @@ ngx_kqueue_process_events(ngx_cycle_t *c err = 0; } - if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { + ngx_time_update(); } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, @@ -595,7 +595,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c #if (NGX_HAVE_TIMER_EVENT) if (event_list[i].filter == EVFILT_TIMER) { - ngx_time_update(0, 0); + ngx_time_update(); continue; } diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -266,8 +266,8 @@ ngx_poll_process_events(ngx_cycle_t *cyc err = 0; } - if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { + ngx_time_update(); } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c --- a/src/event/modules/ngx_rtsig_module.c +++ b/src/event/modules/ngx_rtsig_module.c @@ -323,7 +323,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy "rtsig signo:%d", signo); if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + ngx_time_update(); } if (err == NGX_EAGAIN) { @@ -349,7 +349,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy signo, si.si_fd, si.si_band); if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + ngx_time_update(); } rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module); @@ -419,7 +419,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy } else if (signo == SIGALRM) { - ngx_time_update(0, 0); + ngx_time_update(); return NGX_OK; @@ -671,7 +671,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t * } if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + ngx_time_update(); } ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -266,8 +266,8 @@ ngx_select_process_events(ngx_cycle_t *c err = 0; } - if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { + ngx_time_update(); } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c --- a/src/event/modules/ngx_win32_select_module.c +++ b/src/event/modules/ngx_win32_select_module.c @@ -273,7 +273,7 @@ ngx_select_process_events(ngx_cycle_t *c } if (flags & NGX_UPDATE_TIME) { - ngx_time_update(0, 0); + ngx_time_update(); } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -562,8 +562,6 @@ ngx_timer_signal_handler(int signo) { ngx_event_timer_alarm = 1; - ngx_time_update(0, 0); - #if 1 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer signal"); #endif diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1128,7 +1128,7 @@ ngx_http_file_cache_manager_sleep(ngx_ht if (cache->files++ > 100) { - ngx_time_update(0, 0); + ngx_time_update(); elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); @@ -1145,7 +1145,7 @@ ngx_http_file_cache_manager_sleep(ngx_ht ngx_msleep(200); - ngx_time_update(0, 0); + ngx_time_update(); } cache->last = ngx_current_msec; diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -64,10 +64,22 @@ u_char *ngx_strerror_r(int err, u_char * /* Solaris and Tru64 UNIX have thread-safe strerror() */ -#define ngx_strerror_r(err, errstr, size) \ +#define ngx_strerror_r(err, errstr, size) \ ngx_cpystrn(errstr, (u_char *) strerror(err), size) #endif +#if (NGX_HAVE_SYS_ERRLIST) + +#define ngx_sigsafe_strerror(err) \ + (err > 0 && err < sys_nerr) ? sys_errlist[err] : "Unknown error" + +#else + +#define ngx_sigsafe_strerror(err) "" + +#endif + + #endif /* _NGX_ERRNO_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -315,7 +315,7 @@ ngx_signal_handler(int signo) } } - ngx_time_update(0, 0); + ngx_time_sigsafe_update(); action = ""; @@ -476,16 +476,17 @@ ngx_process_get_status(void) */ if (err == NGX_ECHILD) { - ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno, - "waitpid() failed"); + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, + "waitpid() failed (%d: %s)", + err, ngx_sigsafe_strerror(err)); return; } #endif - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno, - "waitpid() failed"); - + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "waitpid() failed (%d: %s)", + err, ngx_sigsafe_strerror(err)); return; } diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -168,7 +168,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy sigsuspend(&set); - ngx_time_update(0, 0); + ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); @@ -1337,7 +1337,7 @@ ngx_cache_manager_process_handler(ngx_ev next = (n <= next) ? n : next; - ngx_time_update(0, 0); + ngx_time_update(); } } @@ -1367,7 +1367,7 @@ ngx_cache_loader_process_handler(ngx_eve if (path[i]->loader) { path[i]->loader(path[i]->data); - ngx_time_update(0, 0); + ngx_time_update(); } } diff --git a/src/os/win32/ngx_process.c b/src/os/win32/ngx_process.c --- a/src/os/win32/ngx_process.c +++ b/src/os/win32/ngx_process.c @@ -85,7 +85,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ch rc = WaitForMultipleObjects(2, events, 0, 5000); - ngx_time_update(0, 0); + ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "WaitForMultipleObjects: %ul", rc); diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c --- a/src/os/win32/ngx_process_cycle.c +++ b/src/os/win32/ngx_process_cycle.c @@ -140,7 +140,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ev = WaitForMultipleObjects(nev, events, 0, timeout); err = ngx_errno; - ngx_time_update(0, 0); + ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "master WaitForMultipleObjects: %ul", ev); @@ -679,7 +679,7 @@ ngx_worker_process_cycle(ngx_cycle_t *cy ev = WaitForMultipleObjects(3, events, 0, INFINITE); err = ngx_errno; - ngx_time_update(0, 0); + ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "worker WaitForMultipleObjects: %ul", ev); @@ -738,7 +738,7 @@ ngx_worker_process_cycle(ngx_cycle_t *cy ev = WaitForMultipleObjects(nev, events, 0, INFINITE); err = ngx_errno; - ngx_time_update(0, 0); + ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "worker exit WaitForMultipleObjects: %ul", ev); @@ -907,7 +907,7 @@ ngx_cache_manager_thread(void *data) ev = WaitForMultipleObjects(2, events, 0, INFINITE); err = ngx_errno; - ngx_time_update(0, 0); + ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "cache manager WaitForMultipleObjects: %ul", ev); @@ -968,7 +968,7 @@ ngx_cache_manager_process_handler(void) next = (n <= next) ? n : next; - ngx_time_update(0, 0); + ngx_time_update(); } } @@ -980,7 +980,7 @@ ngx_cache_manager_process_handler(void) if (ev != WAIT_TIMEOUT) { - ngx_time_update(0, 0); + ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "cache manager WaitForSingleObject: %ul", ev); @@ -1008,7 +1008,7 @@ ngx_cache_loader_thread(void *data) if (path[i]->loader) { path[i]->loader(path[i]->data); - ngx_time_update(0, 0); + ngx_time_update(); } }