changeset 3587:e1409e56ba7c stable-0.7

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
author Igor Sysoev <igor@sysoev.ru>
date Mon, 07 Jun 2010 10:35:08 +0000
parents 2d21e02fc01d
children d0c46cafc201
files auto/unix src/core/ngx_cycle.c src/core/ngx_times.c src/core/ngx_times.h src/event/modules/ngx_devpoll_module.c src/event/modules/ngx_epoll_module.c src/event/modules/ngx_eventport_module.c src/event/modules/ngx_iocp_module.c src/event/modules/ngx_kqueue_module.c src/event/modules/ngx_poll_module.c src/event/modules/ngx_rtsig_module.c src/event/modules/ngx_select_module.c src/event/modules/ngx_win32_select_module.c src/event/ngx_event.c src/http/ngx_http_file_cache.c src/os/unix/ngx_errno.h src/os/unix/ngx_process.c src/os/unix/ngx_process_cycle.c src/os/win32/ngx_process.c src/os/win32/ngx_process_cycle.c
diffstat 20 files changed, 139 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- 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 <stdio.h>"
+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
--- 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;
--- 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)
 {
--- 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);
--- 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) {
--- 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) {
--- 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;
         }
 
--- 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,
--- 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;
         }
 
--- 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,
--- 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,
--- 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,
--- 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,
--- 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
--- 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;
--- 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_ */
--- 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;
         }
 
--- 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();
         }
     }
 
--- 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);
--- 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();
         }
     }