changeset 370:54f76b0b8dca

nginx-0.0.7-2004-06-27-22:01:57 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 27 Jun 2004 18:01:57 +0000
parents 9c2515d70489
children 780e93985b93
files auto/endianess auto/fmt/fmt auto/fmt/ptrfmt auto/types/maxvalue auto/types/sizeof auto/types/typedef auto/types/uintptr_t auto/types/value auto/unix src/core/ngx_atomic.h src/core/ngx_config.h src/core/ngx_connection.h src/core/ngx_core.h src/core/ngx_garbage_collector.c src/core/ngx_times.c src/core/ngx_times.h src/event/modules/ngx_kqueue_module.c src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_posted.c src/event/ngx_event_posted.h src/http/modules/ngx_http_gzip_filter.c src/http/modules/ngx_http_headers_filter.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/ngx_http_request.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd_rfork_thread.c src/os/unix/ngx_linux_config.h src/os/unix/ngx_process_cycle.c src/os/unix/ngx_solaris_config.h src/os/unix/ngx_thread.h src/os/unix/ngx_time.c
diffstat 32 files changed, 459 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/auto/endianess
@@ -0,0 +1,38 @@
+
+echo $ngx_n "checking for system endianess ..." $ngx_c
+echo >> $NGX_ERR
+echo "checking for system endianess" >> $NGX_ERR
+
+
+cat << END > $NGX_AUTOTEST.c
+
+int main() {
+    int i = 0x11223344;
+    char *p;
+
+    p = (char *) &i;
+    if (*p == 0x44) return 0;
+    return 1;
+}
+
+END
+
+eval "${CC} -o $NGX_AUTOTEST $NGX_AUTOTEST.c >> $NGX_ERR 2>&1"
+
+if [ -x $NGX_AUTOTEST ]; then
+    if $NGX_AUTOTEST 2>&1 > /dev/null; then
+        echo " little endianess"
+        have=HAVE_LITTLE_ENDIAN . auto/have
+    else
+        echo " big endianess"
+    fi
+
+    rm $NGX_AUTOTEST*
+
+else
+    rm $NGX_AUTOTEST*
+
+    echo
+    echo "$0: error: can not detect system endianess"
+    exit 1
+fi
--- a/auto/fmt/fmt
+++ b/auto/fmt/fmt
@@ -11,15 +11,15 @@ do
 
     cat << END > $NGX_AUTOTEST.c
 
-#include <stdio.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#include <stdio.h>
 #include <sys/resource.h>
 $NGX_INTTYPES_H
 $NGX_AUTO_CONFIG
 
 int main() {
-    printf("$fmt", ($ngx_type) $ngx_max_size);
+    printf("$fmt", ($ngx_type) $ngx_max_value);
     return 0;
 }
 
@@ -28,10 +28,10 @@ END
     eval "$CC_WARN $CC_TEST_FLAGS -o $NGX_AUTOTEST $NGX_AUTOTEST.c \
           >> $NGX_ERR 2>&1"
 
-    max_size=`echo $ngx_max_size | sed -e "s/L*\$//"`
+    max_value=`echo $ngx_max_value | sed -e "s/L*\$//"`
 
     if [ -x $NGX_AUTOTEST ]; then
-        if [ "`$NGX_AUTOTEST`" = $max_size ]; then
+        if [ "`$NGX_AUTOTEST`" = $max_value ]; then
             if [ $ngx_fmt_collect = yes ]; then
                 echo $ngx_n "$comma \"${fmt}\" is appropriate" $ngx_c
             else
@@ -45,7 +45,7 @@ END
 
     if [ $ngx_fmt != no ]; then
         if [ $ngx_fmt_collect = yes ]; then
-            eval "ngx_${ngx_bytes}_fmt=\"\${ngx_${ngx_bytes}_fmt} \$ngx_fmt\""
+            eval "ngx_${ngx_size}_fmt=\"\${ngx_${ngx_size}_fmt} \$ngx_fmt\""
             comma=","
             continue
         else
--- a/auto/fmt/ptrfmt
+++ b/auto/fmt/ptrfmt
@@ -13,7 +13,7 @@ do
     cat << END > $NGX_AUTOTEST.c
 
 int main() {
-    printf("$fmt", ($ngx_type) $ngx_max_size);
+    printf("$fmt", ($ngx_type) $ngx_max_value);
     return 0;
 }
 
@@ -22,10 +22,10 @@ END
     eval "$CC_WARN $CC_TEST_FLAGS -o $NGX_AUTOTEST $NGX_AUTOTEST.c \
           >> $NGX_ERR 2>&1"
 
-    max_size=`echo $ngx_max_size | sed -e "s/L*\$//"`
+    max_value=`echo $ngx_max_value | sed -e "s/L*\$//"`
 
     if [ -x $NGX_AUTOTEST ]; then
-        if [ "`$NGX_AUTOTEST`" = $max_size ]; then
+        if [ "`$NGX_AUTOTEST`" = $max_value ]; then
             ngx_fmt=$fmt
         fi
     fi
@@ -49,8 +49,8 @@ if [ $ngx_fmt = no ]; then
 fi
 
 
-if [ $ngx_ptr_bytes = 4 ]; then
-    fmtX="%0`expr 2 \* $ngx_ptr_bytes`"
+if [ $ngx_ptr_size = 4 ]; then
+    fmtX="%0`expr 2 \* $ngx_ptr_size`"
 else
     fmtX="%"
 fi
--- a/auto/types/sizeof
+++ b/auto/types/sizeof
@@ -3,14 +3,15 @@ echo $ngx_n "checking for $ngx_type size
 echo >> $NGX_ERR
 echo "checking for $ngx_type size" >> $NGX_ERR
 
-ngx_bytes=
+ngx_size=
 
 cat << END > $NGX_AUTOTEST.c
 
 #include <sys/types.h>
 #include <sys/time.h>
+$NGX_UNISTD_H
+#include <signal.h>
 #include <sys/resource.h>
-$NGX_UNISTD_H
 $NGX_INTTYPES_H
 $NGX_AUTO_CONFIG
 
@@ -24,27 +25,31 @@ END
 eval "$CC $CC_TEST_FLAGS -o $NGX_AUTOTEST $NGX_AUTOTEST.c >> $NGX_ERR 2>&1"
 
 if [ -x $NGX_AUTOTEST ]; then
-    ngx_bytes=`$NGX_AUTOTEST`
-    echo " $ngx_bytes bytes"
+    ngx_size=`$NGX_AUTOTEST`
+    echo " $ngx_size bytes"
 fi
 
 rm $NGX_AUTOTEST*
 
-case $ngx_bytes in
+case $ngx_size in
     4)
         if [ "$ngx_type"="long" ]; then
-            ngx_max_size=2147483647L
+            ngx_max_value=2147483647L
         else
-            ngx_max_size=2147483647
+            ngx_max_value=2147483647
         fi
+
+        ngx_max_len='sizeof("-2147483648") - 1'
     ;;
 
     8)
         if [ "$ngx_type"="long long" ]; then
-            ngx_max_size=9223372036854775807LL
+            ngx_max_value=9223372036854775807LL
         else
-            ngx_max_size=9223372036854775807L
+            ngx_max_value=9223372036854775807L
         fi
+
+        ngx_max_len='sizeof("-9223372036854775808") - 1'
     ;;
 
     *)
--- a/auto/types/typedef
+++ b/auto/types/typedef
@@ -10,8 +10,8 @@ do
 
     cat << END > $NGX_AUTOTEST.c
 
+#include <sys/types.h>
 #include <signal.h>
-#include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/resource.h>
--- a/auto/types/uintptr_t
+++ b/auto/types/uintptr_t
@@ -30,7 +30,7 @@ rm $NGX_AUTOTEST*
 
 
 if [ $found = no ]; then
-    found="uint`expr 8 \* $ngx_ptr_bytes`_t"
+    found="uint`expr 8 \* $ngx_ptr_size`_t"
     echo ", $found used"
 
     echo "typedef $found  uintptr_t;"   >> $NGX_AUTO_CONFIG_H
rename from auto/types/maxvalue
rename to auto/types/value
--- a/auto/types/maxvalue
+++ b/auto/types/value
@@ -1,6 +1,6 @@
 
 cat << END >> $NGX_AUTO_CONFIG_H
 
-#ifndef $ngx_type_max_value
-#define $ngx_type_max_value  $ngx_max_size
+#ifndef $ngx_param
+#define $ngx_param  $ngx_value
 #endif
--- a/auto/unix
+++ b/auto/unix
@@ -13,32 +13,31 @@ ngx_formats="%ld"; . auto/fmt/fmt
 ngx_type="long long"; . auto/types/sizeof
 ngx_formats="%lld %qd"; . auto/fmt/fmt
 
-ngx_type="void *"; . auto/types/sizeof; ngx_ptr_bytes=$ngx_bytes
+ngx_type="void *"; . auto/types/sizeof; ngx_ptr_size=$ngx_size
 ngx_fmt_name=PTR_FMT;
-eval ngx_formats=\${ngx_${ngx_bytes}_fmt}; . auto/fmt/ptrfmt
+eval ngx_formats=\${ngx_${ngx_ptr_size}_fmt}; . auto/fmt/ptrfmt
 
 
 # POSIX types
 
 NGX_AUTO_CONFIG="#include \"../$NGX_AUTO_CONFIG_H\""
 
-ngx_type="uint64_t"
-ngx_types="u_int64_t"; . auto/types/typedef
+ngx_type="uint64_t"; ngx_types="u_int64_t"; . auto/types/typedef
 
-ngx_type="sig_atomic_t"
-ngx_types="int"; . auto/types/typedef
+ngx_type="sig_atomic_t"; ngx_types="int"; . auto/types/typedef
+. auto/types/sizeof
+ngx_param=SIG_ATOMIC_T_SIZE; ngx_value=$ngx_size; . auto/types/value
 
-ngx_type="socklen_t"
-ngx_types="uint32_t"; . auto/types/typedef
+ngx_type="socklen_t"; ngx_types="uint32_t"; . auto/types/typedef
 
-ngx_type="in_addr_t"
-ngx_types="uint32_t"; . auto/types/typedef
+ngx_type="in_addr_t"; ngx_types="uint32_t"; . auto/types/typedef
 
-ngx_type="rlim_t"
-ngx_types="int"; . auto/types/typedef
+ngx_type="rlim_t"; ngx_types="int"; . auto/types/typedef
 
 . auto/types/uintptr_t
 
+. auto/endianess
+
 
 # printf() formats
 
@@ -46,22 +45,24 @@ CC_WARN=$CC_STRONG
 ngx_fmt_collect=no
 
 ngx_fmt_name=OFF_T_FMT; ngx_type="off_t"; . auto/types/sizeof
-ngx_type_max_value=OFF_T_MAX_VALUE; . auto/types/maxvalue
-eval ngx_formats=\${ngx_${ngx_bytes}_fmt}; . auto/fmt/fmt
+ngx_param=OFF_T_MAX_VALUE; ngx_value=$ngx_max_value; . auto/types/value
+eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
 
 ngx_fmt_name=TIME_T_FMT; ngx_type="time_t"; . auto/types/sizeof
-eval ngx_formats=\${ngx_${ngx_bytes}_fmt}; . auto/fmt/fmt
+ngx_param=TIME_T_SIZE; ngx_value=$ngx_size; . auto/types/value
+ngx_param=TIME_T_LEN; ngx_value=$ngx_max_len; . auto/types/value
+eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
 
 ngx_fmt_name=SIZE_T_FMT; ngx_type="size_t"; . auto/types/sizeof
-eval ngx_formats=\${ngx_${ngx_bytes}_fmt}; . auto/fmt/fmt
+eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
 
 ngx_fmt_name=SIZE_T_X_FMT; . auto/fmt/xfmt
 
 ngx_fmt_name=PID_T_FMT; ngx_type="pid_t"; . auto/types/sizeof
-eval ngx_formats=\${ngx_${ngx_bytes}_fmt}; . auto/fmt/fmt
+eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
 
 ngx_fmt_name=RLIM_T_FMT; ngx_type="rlim_t"; . auto/types/sizeof
-eval ngx_formats=\${ngx_${ngx_bytes}_fmt}; . auto/fmt/fmt
+eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
 
 
 # syscalls, libc calls and some features
--- a/src/core/ngx_atomic.h
+++ b/src/core/ngx_atomic.h
@@ -93,4 +93,18 @@ typedef volatile uint32_t  ngx_atomic_t;
 #endif
 
 
+static ngx_inline ngx_int_t ngx_trylock(ngx_atomic_t *lock)
+{
+    if (*lock) {
+        return NGX_BUSY;
+    }
+
+    if (ngx_atomic_cmp_set(lock, 0, 1)) {
+        return NGX_OK;
+    }
+
+    return NGX_BUSY;
+}
+
+
 #endif /* _NGX_ATOMIC_H_INCLUDED_ */
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -75,10 +75,6 @@ typedef long               ngx_flag_t;
 /* TODO: auto */
 #define NGX_INT32_LEN      sizeof("-2147483648") - 1
 #define NGX_INT64_LEN      sizeof("-9223372036854775808") - 1
-#if 0
-#define NGX_TIME_T_LEN     sizeof("-2147483648") - 1
-#endif
-#define NGX_TIME_T_LEN     sizeof("-9223372036854775808") - 1
 #define NGX_OFF_T_LEN      sizeof("-9223372036854775808") - 1
 
 
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -108,6 +108,10 @@ struct ngx_connection_s {
 #if (HAVE_IOCP)
     unsigned          accept_context_updated:1;
 #endif
+
+#if (NGX_THREADS)
+    ngx_atomic_t      lock;
+#endif
 };
 
 
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -15,6 +15,15 @@ typedef struct ngx_event_s       ngx_eve
 typedef struct ngx_connection_s  ngx_connection_t;
 
 
+#define  NGX_OK          0
+#define  NGX_ERROR      -1
+#define  NGX_AGAIN      -2
+#define  NGX_BUSY       -3
+#define  NGX_DONE       -4
+#define  NGX_DECLINED   -5
+#define  NGX_ABORT      -6
+
+
 #include <ngx_atomic.h>
 #include <ngx_time.h>
 #include <ngx_socket.h>
@@ -49,16 +58,6 @@ typedef struct ngx_connection_s  ngx_con
 #include <ngx_connection.h>
 
 
-
-#define  NGX_OK          0
-#define  NGX_ERROR      -1
-#define  NGX_AGAIN      -2
-#define  NGX_BUSY       -3
-#define  NGX_DONE       -4
-#define  NGX_DECLINED   -5
-#define  NGX_ABORT      -6
-
-
 #define LF     (u_char) 10
 #define CR     (u_char) 13
 #define CRLF   "\x0d\x0a"
--- a/src/core/ngx_garbage_collector.c
+++ b/src/core/ngx_garbage_collector.c
@@ -254,7 +254,7 @@ int ngx_garbage_collector_temp_handler(n
      *    Unices have the mount option "noatime".
      */
 
-    if (ngx_cached_time - ngx_de_mtime(dir) < 3600) {
+    if (ngx_time() - ngx_de_mtime(dir) < 3600) {
         return NGX_OK;
     }
 
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -3,32 +3,62 @@
 #include <ngx_core.h>
 
 
+ngx_epoch_msec_t  ngx_elapsed_msec;
+ngx_epoch_msec_t  ngx_old_elapsed_msec;
+ngx_epoch_msec_t  ngx_start_msec;
+
+static ngx_tm_t   ngx_cached_gmtime;
+static ngx_int_t  ngx_gmtoff;
+
+
+/*
+ * In the threaded mode only one thread updates cached time and strings
+ * and these operations are protected by the mutex.  The reading of the cached
+ * time and strings is not protected by the mutex.  To avoid the race
+ * conditions for non-atomic values we use the NGX_TIME_SLOTS slots to store
+ * time value and strings.  Thus thread may get the corrupted values only
+ * if it is preempted while copying and then it is not scheduled to run
+ * more than NGX_TIME_SLOTS seconds.
+ */
+
 #if (NGX_THREADS)
-static ngx_mutex_t  *ngx_time_mutex;
+
+#define NGX_TIME_SLOTS  60
+static ngx_uint_t       slot = NGX_TIME_SLOTS;
+
+static ngx_mutex_t     *ngx_time_mutex;
+
+#else
+
+#define NGX_TIME_SLOTS  1
+#define slot            0
+
 #endif
 
 
-ngx_epoch_msec_t    ngx_elapsed_msec;
-ngx_epoch_msec_t    ngx_old_elapsed_msec;
-ngx_epoch_msec_t    ngx_start_msec;
+#if (NGX_THREADS && (TIME_T_SIZE > SIG_ATOMIC_T_SIZE))
+
+volatile time_t  *ngx_cached_time;
+static time_t     cached_time[NGX_TIME_SLOTS];
 
-volatile time_t     ngx_cached_time;
+#else
 
-volatile ngx_str_t  ngx_cached_err_log_time;
-volatile ngx_str_t  ngx_cached_http_time;
-volatile ngx_str_t  ngx_cached_http_log_time;
+volatile time_t   ngx_cached_time;
+
+#endif
+
 
-static ngx_tm_t     ngx_cached_gmtime;
-static ngx_int_t    ngx_gmtoff;
+ngx_thread_volatile ngx_str_t  ngx_cached_err_log_time;
+ngx_thread_volatile ngx_str_t  ngx_cached_http_time;
+ngx_thread_volatile ngx_str_t  ngx_cached_http_log_time;
 
-static u_char       cached_err_log_time0[] = "1970/09/28 12:00:00";
-static u_char       cached_err_log_time1[] = "1970/09/28 12:00:00";
 
-static u_char       cached_http_time0[] = "Mon, 28 Sep 1970 06:00:00 GMT";
-static u_char       cached_http_time1[] = "Mon, 28 Sep 1970 06:00:00 GMT";
-
-static u_char       cached_http_log_time0[] = "28/Sep/1970:12:00:00 +0600";
-static u_char       cached_http_log_time1[] = "28/Sep/1970:12:00:00 +0600";
+static u_char  cached_err_log_time[NGX_TIME_SLOTS]
+                                               [sizeof("1970/09/28 12:00:00")];
+static u_char  cached_http_time[NGX_TIME_SLOTS]
+                                     [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
+static u_char  cached_http_log_time[NGX_TIME_SLOTS]
+                                        [sizeof("28/Sep/1970:12:00:00 +0600")];
 
 
 static char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
@@ -45,16 +75,13 @@ void ngx_time_init()
     ngx_cached_gmtime.ngx_tm_zone = "GMT";
 #endif
 
-    ngx_cached_err_log_time.len = sizeof(cached_err_log_time0) - 1;
-    ngx_cached_err_log_time.data = cached_err_log_time0;
+    ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
+    ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
+    ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
 
-    ngx_cached_http_time.len = sizeof(cached_http_time0) - 1;
-    ngx_cached_http_time.data = cached_http_time0;
-
-    ngx_cached_http_log_time.len = sizeof(cached_http_log_time0) - 1;
-    ngx_cached_http_log_time.data = cached_http_log_time0;
-
-    ngx_cached_time = 0;
+#if (TIME_T_SIZE > SIG_ATOMIC_T_SIZE)
+    ngx_cached_time = &cached_time[0];
+#endif
 
     ngx_gettimeofday(&tv);
 
@@ -89,26 +116,34 @@ void ngx_time_update(time_t s)
     u_char    *p;
     ngx_tm_t   tm;
 
-    if (ngx_cached_time == s) {
+    if (ngx_time() == s) {
         return;
     }
 
 #if (NGX_THREADS)
+
     if (ngx_mutex_trylock(ngx_time_mutex) != NGX_OK) {
         return;
     }
+
+    if (slot == NGX_TIME_SLOTS) {
+        slot = 0;
+    } else {
+        slot++;
+    }
+
+#if (TIME_T_SIZE > SIG_ATOMIC_T_SIZE)
+    ngx_cached_time = &cached_time[slot];
 #endif
 
-    ngx_cached_time = s;
+#endif
 
-    ngx_gmtime(ngx_cached_time, &ngx_cached_gmtime);
+    ngx_time() = s;
+
+    ngx_gmtime(s, &ngx_cached_gmtime);
 
 
-    if (ngx_cached_http_time.data == cached_http_time0) {
-        p = cached_http_time1;
-    } else {
-        p = cached_http_time0;
-    }
+    p = cached_http_time[slot];
 
     ngx_snprintf((char *) p, sizeof("Mon, 28 Sep 1970 06:00:00 GMT"),
                  "%s, %02d %s %4d %02d:%02d:%02d GMT",
@@ -126,7 +161,7 @@ void ngx_time_update(time_t s)
 #if (HAVE_GETTIMEZONE)
 
     ngx_gmtoff = ngx_gettimezone();
-    ngx_gmtime(ngx_cached_time + ngx_gmtoff * 60, &tm);
+    ngx_gmtime(s + ngx_gmtoff * 60, &tm);
 
 #elif (HAVE_GMTOFF)
 
@@ -141,11 +176,7 @@ void ngx_time_update(time_t s)
 #endif
 
 
-    if (ngx_cached_err_log_time.data == cached_err_log_time0) {
-        p = cached_err_log_time1;
-    } else {
-        p = cached_err_log_time0;
-    }
+    p = cached_err_log_time[slot];
 
     ngx_snprintf((char *) p, sizeof("1970/09/28 12:00:00"),
                  "%4d/%02d/%02d %02d:%02d:%02d",
@@ -156,11 +187,7 @@ void ngx_time_update(time_t s)
     ngx_cached_err_log_time.data = p;
 
 
-    if (ngx_cached_http_log_time.data == cached_http_log_time0) {
-        p = cached_http_log_time1;
-    } else {
-        p = cached_http_log_time0;
-    }
+    p = cached_http_log_time[slot];
 
     ngx_snprintf((char *) p, sizeof("28/Sep/1970:12:00:00 +0600"),
                  "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d",
--- a/src/core/ngx_times.h
+++ b/src/core/ngx_times.h
@@ -7,17 +7,27 @@
 
 
 void ngx_time_init();
-#if (NGX_THREADS)
-ngx_int_t ngx_time_mutex_init(ngx_log_t *log);
-#endif
 void ngx_time_update(time_t s);
 size_t ngx_http_time(u_char *buf, time_t t);
 void ngx_gmtime(time_t t, ngx_tm_t *tp);
 
-#define ngx_time()   ngx_cached_time
+#if (NGX_THREADS)
+ngx_int_t ngx_time_mutex_init(ngx_log_t *log);
+#endif
+
+#if (NGX_THREADS && (TIME_T_SIZE > SIG_ATOMIC_T_SIZE))
+
+#define ngx_time()        *ngx_cached_time
+extern volatile time_t    *ngx_cached_time;
+
+#else
+
+#define ngx_time()         ngx_cached_time
+extern volatile time_t     ngx_cached_time;
+
+#endif
 
 
-extern volatile time_t     ngx_cached_time;
 extern volatile ngx_str_t  ngx_cached_err_log_time;
 extern volatile ngx_str_t  ngx_cached_http_time;
 extern volatile ngx_str_t  ngx_cached_http_log_time;
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -582,14 +582,17 @@ static ngx_int_t ngx_kqueue_process_even
         ngx_mutex_unlock(ngx_posted_events_mutex);
     }
 
-    /* TODO: wake up worker thread */
-
     if (expire && delta) {
         ngx_event_expire_timers((ngx_msec_t) delta);
     }
 
-    if (!ngx_threaded) {
-        ngx_event_process_posted(cycle);
+    if (ngx_posted_events) {
+        if (ngx_threaded) {
+            ngx_cv_signal(ngx_posted_events_cv);
+
+        } else {
+            ngx_event_process_posted(cycle);
+        }
     }
 
     return NGX_OK;
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -265,6 +265,9 @@ static ngx_int_t ngx_event_process_init(
     for (i = 0; i < cycle->connection_n; i++) {
         c[i].fd = (ngx_socket_t) -1;
         c[i].data = NULL;
+#if (NGX_THREADS)
+        c[i].lock = 0;
+#endif
     }
 
     cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections,
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -154,6 +154,11 @@ struct ngx_event_s {
 #endif
 
 
+#if (NGX_THREADS)
+    ngx_atomic_t    *lock;
+#endif
+
+
 #if 0
 
     /* the threads support */
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -278,6 +278,11 @@ void ngx_event_accept(ngx_event_t *ev)
 
         c->number = ngx_atomic_inc(ngx_connection_counter);
 
+#if (NGX_THREADS)
+        rev->lock = &c->lock;
+        wev->lock = &c->lock;
+#endif
+
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                        "accept: fd:%d c:%d", s, c->number);
 
--- a/src/event/ngx_event_posted.c
+++ b/src/event/ngx_event_posted.c
@@ -5,8 +5,10 @@
 
 
 ngx_thread_volatile ngx_event_t  *ngx_posted_events;
+
 #if (NGX_THREADS)
 ngx_mutex_t                      *ngx_posted_events_mutex;
+ngx_cv_t                         *ngx_posted_events_cv;
 #endif
 
 
@@ -55,26 +57,70 @@ void ngx_event_process_posted(ngx_cycle_
 
 #if (NGX_THREADS)
 
-void ngx_event_thread_handler(ngx_event_t *ev)
+ngx_int_t ngx_event_thread_process_posted(ngx_cycle_t *cycle)
 {
-    if ((!ev->posted && !ev->active)
-        || (ev->use_instance && ev->instance != ev->returned_instance))
-    {
-        /*
-         * the stale event from a file descriptor
-         * that was just closed in this iteration
-         */
+    ngx_event_t  *ev, **ep;
+
+    for ( ;; ) {
+
+        ev = (ngx_event_t *) ngx_posted_events;
+        ep = (ngx_event_t **) &ngx_posted_events;
+
+        for ( ;; ) {
+
+            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                          "posted event " PTR_FMT, ev);
+
+            if (ev == NULL) {
+                ngx_mutex_unlock(ngx_posted_events_mutex);
+                return NGX_OK;
+            }
+
+            if (ngx_trylock(ev->lock) == NGX_BUSY) {
+
+                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                               "posted event " PTR_FMT " is busy", ev);
+
+                ep = &ev->next;
+                ev = ev->next;
+                continue;
+            }
+
+            *ep = ev->next;
 
-        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
-                       "kevent: stale event " PTR_FMT, ev);
-        return;
-    }
+            if ((!ev->posted && !ev->active)
+                || (ev->use_instance && ev->instance != ev->returned_instance))
+            {
+                /*
+                 * the stale event from a file descriptor
+                 * that was just closed in this iteration
+                 */
+
+                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+                               "kevent: stale event " PTR_FMT, ev);
+
+                ev = ev->next;
+
+                continue;
+            }
 
-    if (ev->posted) {
-        ev->posted = 0;
+            ngx_mutex_unlock(ngx_posted_events_mutex);
+
+            if (ev->posted) {
+                ev->posted = 0;
+            }
+
+            ev->event_handler(ev);
+
+            *(ev->lock) = 0;
+
+            if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            break;
+        }
     }
-
-    ev->event_handler(ev);
 }
 
 #endif
--- a/src/event/ngx_event_posted.h
+++ b/src/event/ngx_event_posted.h
@@ -14,14 +14,15 @@
 
 
 void ngx_event_process_posted(ngx_cycle_t *cycle);
-#if (NGX_THREADS)
-void ngx_event_thread_handler(ngx_event_t *ev);
-#endif
+
+extern ngx_thread_volatile ngx_event_t  *ngx_posted_events;
 
 
-extern ngx_thread_volatile ngx_event_t  *ngx_posted_events;
 #if (NGX_THREADS)
+ngx_int_t ngx_event_thread_process_posted(ngx_cycle_t *cycle);
+
 extern ngx_mutex_t                      *ngx_posted_events_mutex;
+extern ngx_cv_t                         *ngx_posted_events_cv;
 #endif
 
 
--- a/src/http/modules/ngx_http_gzip_filter.c
+++ b/src/http/modules/ngx_http_gzip_filter.c
@@ -351,7 +351,7 @@ static ngx_int_t ngx_http_gzip_proxied(n
             }
 
         } else {
-            date = ngx_cached_time;
+            date = ngx_time();
         }
 
         if (expires < date) {
--- a/src/http/modules/ngx_http_headers_filter.c
+++ b/src/http/modules/ngx_http_headers_filter.c
@@ -118,24 +118,22 @@ static ngx_int_t ngx_http_headers_filter
                 cc->value.data = (u_char *) "max-age=0";
 
             } else {
-                ngx_http_time(expires->value.data,
-                              ngx_cached_time + conf->expires);
+                ngx_http_time(expires->value.data, ngx_time() + conf->expires);
 
                 if (conf->expires < 0) {
                     cc->value.len = sizeof("no-cache") - 1;
                     cc->value.data = (u_char *) "no-cache";
 
                 } else {
-                    cc->value.data = ngx_palloc(r->pool, NGX_TIME_T_LEN + 1);
+                    cc->value.data = ngx_palloc(r->pool, TIME_T_LEN + 1);
                     if (cc->value.data == NULL) {
                         return NGX_ERROR;
                     }
 
                     cc->value.len = ngx_snprintf((char *) cc->value.data,
-                                                 sizeof("max-age=")
-                                                              + NGX_TIME_T_LEN,
-                                                 "max-age=" TIME_T_FMT,
-                                                 conf->expires);
+                                               sizeof("max-age=") + TIME_T_LEN,
+                                               "max-age=" TIME_T_FMT,
+                                               conf->expires);
                 }
             }
         }
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -708,7 +708,7 @@ static u_char *ngx_http_proxy_log_proxy_
         *buf++ = '-';
 
     } else {
-        buf += ngx_snprintf((char *) buf, NGX_TIME_T_LEN,
+        buf += ngx_snprintf((char *) buf, TIME_T_LEN,
                             TIME_T_FMT, p->state->expired);
     }
 
@@ -718,7 +718,7 @@ static u_char *ngx_http_proxy_log_proxy_
         *buf++ = '-';
 
     } else {
-        buf += ngx_snprintf((char *) buf, NGX_TIME_T_LEN,
+        buf += ngx_snprintf((char *) buf, TIME_T_LEN,
                             TIME_T_FMT, p->state->bl_time);
     }
 
@@ -752,7 +752,7 @@ static u_char *ngx_http_proxy_log_proxy_
         *buf++ = '-';
 
     } else {
-        buf += ngx_snprintf((char *) buf, NGX_TIME_T_LEN,
+        buf += ngx_snprintf((char *) buf, TIME_T_LEN,
                             TIME_T_FMT, p->state->expires);
     }
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1463,7 +1463,7 @@ static void ngx_http_set_lingering_close
     rev = c->read;
     rev->event_handler = ngx_http_lingering_close_handler;
 
-    r->lingering_time = ngx_cached_time + clcf->lingering_time / 1000;
+    r->lingering_time = ngx_time() + clcf->lingering_time / 1000;
     ngx_add_timer(rev, clcf->lingering_timeout);
 
     if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
@@ -1526,7 +1526,7 @@ static void ngx_http_lingering_close_han
         return;
     }
 
-    timer = r->lingering_time - ngx_cached_time;
+    timer = r->lingering_time - ngx_time();
     if (timer <= 0) {
         ngx_http_close_request(r, 0);
         ngx_http_close_connection(c);
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -108,14 +108,9 @@ pid_t rfork_thread(int flags, void *stac
 #endif
 
 
-/* STUB: autoconf */
 #define ngx_setproctitle  setproctitle
 
 
-/* STUB */
-#define HAVE_LITTLE_ENDIAN  1
-
-
 extern char *malloc_options;
 
 
--- a/src/os/unix/ngx_freebsd_rfork_thread.c
+++ b/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -8,26 +8,28 @@
 #include <ngx_core.h>
 
 /*
- * The threads implementation uses the rfork(RFPROC|RFTHREAD|RFMEM)
+ * The threads implementation uses the rfork(RFPROC|RFTHREAD|RFMEM) syscall
  * to create threads.  All threads use the stacks of the same size mmap()ed
- * below the main stack.  Thus the stack pointer is used to determine
- * the current thread id.
+ * below the main stack.  Thus the current thread id is determinated through
+ * the stack pointer.
  *
  * The mutex implementation uses the ngx_atomic_cmp_set() operation
- * to acquire mutex and the SysV semaphore to wait on a mutex or to wake up
- * the waiting threads.
+ * to acquire a mutex and the SysV semaphore to wait on a mutex or to wake up
+ * the waiting threads.  The light mutex does not use semaphore, so after
+ * spinning in the lock the thread calls sched_yield().  However the light
+ * mutecies are intended to be used with the "trylock" operation only.
  *
  * The condition variable implementation uses the SysV semaphore set of two
  * semaphores. The first is used by the CV mutex, and the second is used
- * by CV itself.
+ * by the CV to signal.
  *
- * This threads implementation currently works on i486 and amd64
+ * This threads implementation currently works on i386 (486+) and amd64
  * platforms only.
  */
 
 
-char       *ngx_freebsd_kern_usrstack;
-size_t      ngx_thread_stack_size;
+char               *ngx_freebsd_kern_usrstack;
+size_t              ngx_thread_stack_size;
 
 
 static size_t       rz_size;
@@ -261,7 +263,6 @@ ngx_tid_t ngx_thread_self()
 
 ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, uint flags)
 {
-    int           nsem, i;
     ngx_mutex_t  *m;
     union semun   op;
 
@@ -277,27 +278,23 @@ ngx_mutex_t *ngx_mutex_init(ngx_log_t *l
         return m;
     }
 
-    nsem = flags & NGX_MUTEX_CV ? 2 : 1;
-
-    m->semid = semget(IPC_PRIVATE, nsem, SEM_R|SEM_A);
+    m->semid = semget(IPC_PRIVATE, 1, SEM_R|SEM_A);
     if (m->semid == -1) {
         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semget() failed");
         return NULL;
     }
 
     op.val = 0;
-    for (i = 0; i < nsem; i++) {
-        if (semctl(m->semid, i, SETVAL, op) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                          "semctl(SETVAL) failed");
+
+    if (semctl(m->semid, 0, SETVAL, op) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semctl(SETVAL) failed");
 
-            if (semctl(m->semid, 0, IPC_RMID) == -1) {
-                ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno,
-                              "semctl(IPC_RMID) failed");
-            }
+        if (semctl(m->semid, 0, IPC_RMID) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                          "semctl(IPC_RMID) failed");
+        }
 
-            return NULL;
-        }
+        return NULL;
     }
 
     return m;
@@ -388,7 +385,7 @@ ngx_int_t ngx_mutex_dolock(ngx_mutex_t *
                  * The number of the waiting threads has been increased
                  * and we would wait on the SysV semaphore.
                  * A semaphore should wake up us more efficiently than
-                 * a simple usleep().
+                 * a simple sched_yield() or usleep().
                  */
 
                 op.sem_num = 0;
@@ -456,7 +453,7 @@ ngx_int_t ngx_mutex_unlock(ngx_mutex_t *
 
     if (!(old & NGX_MUTEX_LOCK_BUSY)) {
         ngx_log_error(NGX_LOG_ALERT, m->log, 0,
-                      "tring to unlock the free mutex " PTR_FMT, m);
+                      "trying to unlock the free mutex " PTR_FMT, m);
         return NGX_ERROR;
     }
 
@@ -479,7 +476,7 @@ ngx_int_t ngx_mutex_unlock(ngx_mutex_t *
         return NGX_OK;
     }
 
-    /* check weather we need to wake up a waiting thread */
+    /* check whether we need to wake up a waiting thread */
 
     old = m->lock;
 
@@ -525,3 +522,108 @@ ngx_int_t ngx_mutex_unlock(ngx_mutex_t *
 
     return NGX_OK;
 }
+
+
+ngx_cv_t *ngx_cv_init(ngx_log_t *log)
+{
+    ngx_cv_t     *cv;
+    u_short       val[2];
+    union semun   op;
+
+    if (!(cv = ngx_alloc(sizeof(ngx_cv_t), log))) {
+        return NULL;
+    }
+
+    cv->mutex.lock = 0;
+    cv->mutex.log = log;
+
+    cv->mutex.semid = semget(IPC_PRIVATE, 2, SEM_R|SEM_A);
+    if (cv->mutex.semid == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semget() failed");
+        return NULL;
+    }
+
+    val[0] = 0;
+    val[1] = 0;
+    op.array = val;
+
+    if (semctl(cv->mutex.semid, 0, SETALL, op) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semctl(SETALL) failed");
+
+        if (semctl(cv->mutex.semid, 0, IPC_RMID) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                          "semctl(IPC_RMID) failed");
+        }
+
+        return NULL;
+    }
+
+    return cv;
+}
+
+
+void ngx_cv_done(ngx_cv_t *cv)
+{
+    if (semctl(cv->mutex.semid, 0, IPC_RMID) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, cv->mutex.log, ngx_errno,
+                      "semctl(IPC_RMID) failed");
+    }
+
+    ngx_free(cv);
+}
+
+
+ngx_int_t ngx_cv_wait(ngx_cv_t *cv)
+{
+    struct sembuf  op[2];
+
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->mutex.log, 0,
+                   "cv " PTR_FMT " wait", cv);
+
+    op[0].sem_num = 0;
+    op[0].sem_op = -1;
+    op[0].sem_flg = SEM_UNDO;
+
+    op[1].sem_num = 1;
+    op[1].sem_op = -1;
+    op[1].sem_flg = SEM_UNDO;
+
+    if (semop(cv->mutex.semid, op, 2) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, cv->mutex.log, ngx_errno,
+                      "semop() failed while waiting on cv " PTR_FMT, cv);
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->mutex.log, 0,
+                   "cv " PTR_FMT " is waked up", cv);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t ngx_cv_signal(ngx_cv_t *cv)
+{
+    struct sembuf  op[2];
+
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->mutex.log, 0,
+                   "cv " PTR_FMT " to signal", cv);
+
+    op[0].sem_num = 0;
+    op[0].sem_op = 1;
+    op[0].sem_flg = SEM_UNDO;
+
+    op[1].sem_num = 1;
+    op[1].sem_op = 1;
+    op[1].sem_flg = SEM_UNDO;
+
+    if (semop(cv->mutex.semid, op, 2) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, cv->mutex.log, ngx_errno,
+                      "semop() failed while signaling cv " PTR_FMT, cv);
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->mutex.log, 0,
+                   "cv " PTR_FMT " is signaled", cv);
+
+    return NGX_OK;
+}
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -91,8 +91,4 @@ extern ssize_t sendfile(int s, int fd, i
 #define ngx_setproctitle(title)
 
 
-/* STUB */
-#define HAVE_LITTLE_ENDIAN  1
-
-
 #endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -625,6 +625,13 @@ static void ngx_worker_process_cycle(ngx
         exit(2);
     }
 
+    if (!(ngx_posted_events_cv = ngx_cv_init(cycle->log))) {
+        /* fatal */
+        exit(2);
+    }
+
+    ngx_posted_events_mutex = &ngx_posted_events_cv->mutex;
+
     for (i = 0; i < 1; i++) {
         if (ngx_create_thread(&tid, ngx_worker_thread_cycle,
                               cycle, cycle->log) != 0)
@@ -767,23 +774,25 @@ int ngx_worker_thread_cycle(void *data)
         return 1;
     }
 
-
-    /* STUB */
-
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, ngx_errno,
                    "thread %d started", ngx_thread_self());
 
     ngx_setproctitle("worker thread");
 
-    sleep(5);
+    for ( ;; ) {
+        if (ngx_cv_wait(ngx_posted_events_cv) == NGX_ERROR) {
+            return 1;
+        }
 
-    ngx_gettimeofday(&tv);
-    ngx_time_update(tv.tv_sec);
+        if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) {
+            return 1;
+        }
+    }
 
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, ngx_errno,
                    "thread %d done", ngx_thread_self());
 
-    return 1;
+    return 0;
 }
 
 #endif
--- a/src/os/unix/ngx_solaris_config.h
+++ b/src/os/unix/ngx_solaris_config.h
@@ -76,8 +76,4 @@
 #define ngx_setproctitle(title)
 
 
-/* STUB */
-#define HAVE_LITTLE_ENDIAN  1
-
-
 #endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */
--- a/src/os/unix/ngx_thread.h
+++ b/src/os/unix/ngx_thread.h
@@ -36,6 +36,11 @@ typedef volatile struct {
 } ngx_mutex_t;
 
 
+typedef struct {
+    ngx_mutex_t   mutex;
+} ngx_cv_t;
+
+
 #define ngx_thread_sigmask(how, set, oset)                         \
             (sigprocmask(how, set, oset) == -1) ? ngx_errno : 0
 
@@ -102,6 +107,12 @@ ngx_int_t ngx_mutex_dolock(ngx_mutex_t *
 ngx_int_t ngx_mutex_unlock(ngx_mutex_t *m);
 
 
+ngx_cv_t *ngx_cv_init(ngx_log_t *log);
+void ngx_cv_done(ngx_cv_t *cv);
+ngx_int_t ngx_cv_wait(ngx_cv_t *cv);
+ngx_int_t ngx_cv_signal(ngx_cv_t *cv);
+
+
 #else /* !NGX_THREADS */
 
 #define ngx_thread_volatile
--- a/src/os/unix/ngx_time.c
+++ b/src/os/unix/ngx_time.c
@@ -6,13 +6,17 @@
 void ngx_localtime(ngx_tm_t *tm)
 {
 #if (HAVE_LOCALTIME_R)
+    time_t     now;
 
-    localtime_r((time_t *) &ngx_cached_time, tm);
+    now = ngx_time();
+    localtime_r(&now, tm);
 
 #else
+    time_t     now;
     ngx_tm_t  *t;
 
-    t = localtime((time_t *) &ngx_cached_time);
+    now = ngx_time();
+    t = localtime(&now);
     *tm = *t;
 
 #endif