changeset 306:6b91bfbc4123

nginx-0.0.3-2004-04-05-00:32:09 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 04 Apr 2004 20:32:09 +0000
parents 4b1a3a4acc60
children ce375c313e96
files auto/cc auto/lib/md5/conf auto/lib/pcre/conf auto/lib/zlib/conf auto/sources src/core/ngx_conf_file.h src/event/modules/ngx_epoll_module.c src/event/modules/ngx_kqueue_module.c src/event/modules/ngx_rtsig_module.c src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_connect.c src/event/ngx_event_posted.c src/event/ngx_event_posted.h src/event/ngx_event_timer.c src/http/modules/proxy/ngx_http_proxy_handler.c src/os/unix/ngx_process.c src/os/win32/ngx_process_cycle.c
diffstat 19 files changed, 371 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/auto/cc
+++ b/auto/cc
@@ -2,7 +2,7 @@
 case $CC in
 
     *gcc*)
-         # gcc 2.95.4, 3.3.2
+         # gcc 2.7.2.3, 2.95.4, 3.3.2, 3.4
 
          # optimization
          #CFLAGS="$CFLAGS -O2 -fomit-frame-pointer"
--- a/auto/lib/md5/conf
+++ b/auto/lib/md5/conf
@@ -32,7 +32,8 @@ if [ $MD5 != NONE ]; then
 
         *)
             LINK_DEPS="$LINK_DEPS $MD5/libmd5.a"
-            CORE_LIBS="$CORE_LIBS -L $MD5 -lmd5"
+            CORE_LIBS="$CORE_LIBS $MD5/libmd5.a"
+            #CORE_LIBS="$CORE_LIBS -L $MD5 -lmd5"
         ;;
 
     esac
--- a/auto/lib/pcre/conf
+++ b/auto/lib/pcre/conf
@@ -31,7 +31,8 @@ if [ $PCRE != NONE ]; then
             have=HAVE_PCRE . auto/have
             CORE_DEPS="$CORE_DEPS $PCRE/pcre.h"
             LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a"
-            CORE_LIBS="$CORE_LIBS -L $PCRE/.libs -lpcre"
+            CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a"
+            #CORE_LIBS="$CORE_LIBS -L $PCRE/.libs -lpcre"
         ;;
 
     esac
--- a/auto/lib/zlib/conf
+++ b/auto/lib/zlib/conf
@@ -26,7 +26,8 @@ if [ $ZLIB != NONE ]; then
 
         *)
             LINK_DEPS="$LINK_DEPS $ZLIB/libz.a"
-            CORE_LIBS="$CORE_LIBS -L $ZLIB -lz"
+            CORE_LIBS="$CORE_LIBS $ZLIB/libz.a"
+            #CORE_LIBS="$CORE_LIBS -L $ZLIB -lz"
         ;;
 
     esac
--- a/auto/sources
+++ b/auto/sources
@@ -52,12 +52,14 @@ EVENT_INCS="src/event src/event/modules"
 
 EVENT_DEPS="src/event/ngx_event.h \
             src/event/ngx_event_timer.h \
+            src/event/ngx_event_posted.h \
             src/event/ngx_event_busy_lock.h \
             src/event/ngx_event_connect.h \
             src/event/ngx_event_pipe.h"
 
 EVENT_SRCS="src/event/ngx_event.c \
             src/event/ngx_event_timer.c \
+            src/event/ngx_event_posted.c \
             src/event/ngx_event_busy_lock.c \
             src/event/ngx_event_accept.c \
             src/event/ngx_event_connect.c \
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -176,12 +176,12 @@ char *ngx_conf_check_num_bounds(ngx_conf
     }
 
 #define ngx_conf_init_size_value(conf, default)                              \
-    if (conf == NGX_CONF_UNSET) {                                            \
+    if (conf == NGX_CONF_UNSET_SIZE) {                                       \
         conf = default;                                                      \
     }
 
 #define ngx_conf_init_msec_value(conf, default)                              \
-    if (conf == NGX_CONF_UNSET) {                                            \
+    if (conf == NGX_CONF_UNSET_MSEC) {                                       \
         conf = default;                                                      \
     }
 
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -168,10 +168,11 @@ static int ngx_epoll_init(ngx_cycle_t *c
     ngx_event_actions = ngx_epoll_module_ctx.actions;
 
 #if (HAVE_CLEAR_EVENT)
-    ngx_event_flags = NGX_USE_CLEAR_EVENT;
+    ngx_event_flags = NGX_USE_CLEAR_EVENT
 #else
-    ngx_event_flags = NGX_USE_LEVEL_EVENT;
+    ngx_event_flags = NGX_USE_LEVEL_EVENT
 #endif
+                      |NGX_HAVE_INSTANCE_EVENT;
 
     return NGX_OK;
 }
@@ -257,7 +258,7 @@ static int ngx_epoll_del_event(ngx_event
     /*
      * when the file descriptor is closed the epoll automatically deletes
      * it from its queue so we do not need to delete explicity the event
-     * before the closing the file descriptor.
+     * before the closing the file descriptor
      */
 
     if (flags & NGX_CLOSE_EVENT) {
@@ -339,21 +340,36 @@ static int ngx_epoll_del_connection(ngx_
 
 int ngx_epoll_process_events(ngx_cycle_t *cycle)
 {
-    int                 events;
-    ngx_int_t           instance, i;
-    size_t              n;
-    ngx_msec_t          timer;
-    ngx_err_t           err;
-    struct timeval      tv;
-    ngx_connection_t   *c;
-    ngx_epoch_msec_t    delta;
-
+    int                events;
+    ngx_int_t          instance, i;
+    ngx_uint_t         lock, expire;
+    size_t             n;
+    ngx_msec_t         timer;
+    ngx_err_t          err;
+    struct timeval     tv;
+    ngx_connection_t  *c;
+    ngx_epoch_msec_t   delta;
 
     timer = ngx_event_find_timer();
     ngx_old_elapsed_msec = ngx_elapsed_msec;
 
     if (timer == 0) {
         timer = (ngx_msec_t) -1;
+        expire = 0;
+
+    } else {
+        expire = 1;
+    }
+
+    if (ngx_accept_mutex) {
+        if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        if (ngx_accept_mutex_held == 0 && timer > ngx_accept_mutex_delay) {
+            timer = ngx_accept_mutex_delay;
+            expire = 0;
+        }
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
@@ -382,6 +398,7 @@ int ngx_epoll_process_events(ngx_cycle_t
         if (events == 0) {
             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                           "epoll_wait() returned no events without timeout");
+            ngx_accept_mutex_unlock();
             return NGX_ERROR;
         }
     }
@@ -389,9 +406,17 @@ int ngx_epoll_process_events(ngx_cycle_t
     if (err) {
         ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
                       cycle->log, err, "epoll_wait() failed");
+        ngx_accept_mutex_unlock();
         return NGX_ERROR;
     }
 
+    if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+        ngx_accept_mutex_unlock();
+        return NGX_ERROR;
+    }
+
+    lock = 1;
+
     for (i = 0; i < events; i++) {
         c = event_list[i].data.ptr;
 
@@ -434,25 +459,68 @@ int ngx_epoll_process_events(ngx_cycle_t
                           c->fd, event_list[i].events);
         }
 
+        if ((event_list[i].events & (EPOLLOUT|EPOLLERR|EPOLLHUP))
+            && c->write->active)
+        {
+            c->write->ready = 1;
+
+            if (!ngx_threaded && !ngx_accept_mutex_held) {
+                c->write->event_handler(c->write);
+
+            } else {
+                ngx_post_event(c->write);
+            }
+        }
+
+        /*
+         * EPOLLIN must be handled after EPOLLOUT because we use
+         * the optimization to avoid the unnecessary mutex locking/unlocking
+         * if the accept event is the last one.
+         */
+
         if ((event_list[i].events & (EPOLLIN|EPOLLERR|EPOLLHUP))
             && c->read->active)
         {
             c->read->ready = 1;
-            c->read->event_handler(c->read);
-        }
+
+            if (!ngx_threaded && !ngx_accept_mutex_held) {
+                c->read->event_handler(c->read);
+
+            } else if (!c->read->accept) {
+                ngx_post_event(c->read);
+
+            } else {
+                ngx_mutex_unlock(ngx_posted_events_mutex);
 
-        if ((event_list[i].events & (EPOLLOUT|EPOLLERR|EPOLLHUP))
-            && c->write->active)
-        {
-            c->write->ready = 1;
-            c->write->event_handler(c->write);
+                c->read->event_handler(c->read);
+
+                if (i + 1 == events) {
+                    lock = 0;
+                    break;
+                }
+
+                if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+                    ngx_accept_mutex_unlock();
+                    return NGX_ERROR;
+                }
+            }
         }
     }
 
-    if (timer != (ngx_msec_t) -1 && delta) {
+    if (lock) {
+        ngx_mutex_unlock(ngx_posted_events_mutex);
+    }
+
+    ngx_accept_mutex_unlock();
+
+    if (expire && delta) {
         ngx_event_expire_timers((ngx_msec_t) delta);
     }
 
+    if (!ngx_threaded) {
+        ngx_event_process_posted(cycle);
+    }
+
     return NGX_OK;
 }
 
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -22,9 +22,6 @@ static int ngx_kqueue_add_event(ngx_even
 static int ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags);
 static int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags);
 static int ngx_kqueue_process_events(ngx_cycle_t *cycle);
-#if (NGX_THREADS)
-static void ngx_kqueue_thread_handler(ngx_event_t *ev);
-#endif
 
 static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
 static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
@@ -71,9 +68,6 @@ ngx_event_module_t  ngx_kqueue_module_ct
         NULL,                              /* add an connection */
         NULL,                              /* delete an connection */
         ngx_kqueue_process_events,         /* process the events */
-#if (NGX_THREADS0)
-        ngx_kqueue_thread_handler,         /* process an event by thread */
-#endif
         ngx_kqueue_init,                   /* init the events */
         ngx_kqueue_done                    /* done the events */
     }
@@ -161,6 +155,7 @@ static int ngx_kqueue_init(ngx_cycle_t *
 #if (HAVE_LOWAT_EVENT)
                      |NGX_HAVE_LOWAT_EVENT
 #endif
+                     |NGX_HAVE_INSTANCE_EVENT
                      |NGX_HAVE_KQUEUE_EVENT;
 
     return NGX_OK;
@@ -346,8 +341,8 @@ static int ngx_kqueue_set_event(ngx_even
 static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle)
 {
     int                events;
-    ngx_int_t          i;
-    ngx_uint_t         instance;
+    ngx_int_t          i, instance;
+    ngx_uint_t         lock, expire;
     ngx_err_t          err;
     ngx_msec_t         timer;
     ngx_event_t       *ev;
@@ -364,23 +359,25 @@ static ngx_int_t ngx_kqueue_process_even
 
     /*
      * TODO: if timer is 0 and any worker thread is still busy
-     *       then set 1 second timeout
+     *       then set 500 ms timeout
      */
 
 #endif
 
     ngx_old_elapsed_msec = ngx_elapsed_msec;
+    expire = 1;
 
     if (ngx_accept_mutex) {
         if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
             return NGX_ERROR;
         }
 
-#if 1
-        if (ngx_accept_mutex_held == 0 && timer == 0) {
-            /* STUB */ timer = 500;
+        if (ngx_accept_mutex_held == 0
+            && (timer == 0 || timer > ngx_accept_mutex_delay))
+        {
+            timer = ngx_accept_mutex_delay;
+            expire = 0;
         }
-#endif
     }
 
     if (timer) {
@@ -390,6 +387,7 @@ static ngx_int_t ngx_kqueue_process_even
 
     } else {
         tp = NULL;
+        expire = 0;
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
@@ -441,6 +439,8 @@ static ngx_int_t ngx_kqueue_process_even
         return NGX_ERROR;
     }
 
+    lock = 1;
+
     for (i = 0; i < events; i++) {
 
         ngx_log_debug6(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
@@ -517,106 +517,49 @@ static ngx_int_t ngx_kqueue_process_even
             continue;
         }
 
-
-        if (ngx_threaded || ngx_accept_mutex_held) {
-
-            if (ev->accept) {
-                ngx_mutex_unlock(ngx_posted_events_mutex);
-
-                ev->event_handler(ev);
+        if (!ngx_threaded && !ngx_accept_mutex_held) {
+            ev->event_handler(ev);
+            continue;
+        }
 
-                if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
-                    ngx_accept_mutex_unlock();
-                    return NGX_ERROR;
-                }
-
-            } else {
-                ev->next = (ngx_event_t *) ngx_posted_events;
-                ngx_posted_events = ev;
-            }
-
+        if (!ev->accept) {
+            ngx_post_event(ev);
             continue;
         }
 
+        ngx_mutex_unlock(ngx_posted_events_mutex);
+
         ev->event_handler(ev);
+
+        if (i + 1 == events) {
+            lock = 0;
+            break;
+        }
+
+        if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+            ngx_accept_mutex_unlock();
+            return NGX_ERROR;
+        }
     }
 
-    ngx_mutex_unlock(ngx_posted_events_mutex);
+    if (lock) {
+        ngx_mutex_unlock(ngx_posted_events_mutex);
+    }
 
     ngx_accept_mutex_unlock();
 
-    if (timer && delta) {
+    if (expire && delta) {
         ngx_event_expire_timers((ngx_msec_t) delta);
     }
 
-    if (ngx_threaded) {
-        return NGX_OK;
-    }
-
-    for ( ;; ) {
-
-        ev = (ngx_event_t *) ngx_posted_events;
-
-        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
-                      "kevent: posted event " PTR_FMT, ev);
-
-        if (ev == NULL) {
-            break;
-        }
-
-        ngx_posted_events = ev->next;
-
-        if ((!ev->posted && !ev->active)
-            || 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, cycle->log, 0,
-                          "kevent: stale event " PTR_FMT, ev);
-            continue;
-        }
-
-        if (ev->posted) {
-            ev->posted = 0;
-        }
-
-        ev->event_handler(ev);
+    if (!ngx_threaded) {
+        ngx_event_process_posted(cycle);
     }
 
     return NGX_OK;
 }
 
 
-#if (NGX_THREADS)
-
-static void ngx_kqueue_thread_handler(ngx_event_t *ev)
-{
-    if ((!ev->posted && !ev->active)
-        || 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);
-        return;
-    }
-
-    if (ev->posted) {
-        ev->posted = 0;
-    }
-
-    ev->event_handler(ev);
-}
-
-#endif
-
-
 static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle)
 {
     ngx_kqueue_conf_t  *kcf;
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -117,7 +117,7 @@ static int ngx_rtsig_init(ngx_cycle_t *c
 
     ngx_event_actions = ngx_rtsig_module_ctx.actions;
 
-    ngx_event_flags = NGX_USE_SIGIO_EVENT;
+    ngx_event_flags = NGX_USE_SIGIO_EVENT|NGX_HAVE_INSTANCE_EVENT;
 
     return NGX_OK;
 }
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -49,12 +49,8 @@ ngx_event_actions_t               ngx_ev
 ngx_atomic_t                     *ngx_accept_mutex_ptr;
 ngx_atomic_t                     *ngx_accept_mutex;
 ngx_uint_t                        ngx_accept_mutex_held;
-
+ngx_msec_t                        ngx_accept_mutex_delay;
 
-ngx_thread_volatile ngx_event_t  *ngx_posted_events;
-#if (NGX_THREADS)
-ngx_mutex_t                      *ngx_posted_events_mutex;
-#endif
 
 
 static ngx_str_t  events_name = ngx_string("events");
@@ -114,6 +110,13 @@ static ngx_command_t  ngx_event_core_com
       offsetof(ngx_event_conf_t, accept_mutex),
       NULL },
 
+    { ngx_string("accept_mutex_delay"),
+      NGX_EVENT_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      0,
+      offsetof(ngx_event_conf_t, accept_mutex_delay),
+      NULL },
+
       ngx_null_command
 };
 
@@ -186,10 +189,12 @@ static ngx_int_t ngx_event_process_init(
 
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+    ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
 
     if (ccf->worker_processes > 1 && ngx_accept_mutex_ptr) {
         ngx_accept_mutex = ngx_accept_mutex_ptr;
         ngx_accept_mutex_held = 1;
+        ngx_accept_mutex_delay = ecf->accept_mutex_delay;
     }
 
 #if (NGX_THREADS)
@@ -202,8 +207,6 @@ static ngx_int_t ngx_event_process_init(
         return NGX_ERROR;
     }
 
-    ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
-
     cycle->connection_n = ecf->connections;
 
     for (m = 0; ngx_modules[m]; m++) {
@@ -525,6 +528,7 @@ static void *ngx_event_create_conf(ngx_c
     ecf->use = NGX_CONF_UNSET;
     ecf->multi_accept = NGX_CONF_UNSET;
     ecf->accept_mutex = NGX_CONF_UNSET;
+    ecf->accept_mutex_delay = NGX_CONF_UNSET_MSEC;
     ecf->name = (void *) NGX_CONF_UNSET;
 
     return ecf;
@@ -598,6 +602,7 @@ static char *ngx_event_init_conf(ngx_cyc
 
     ngx_conf_init_value(ecf->multi_accept, 0);
     ngx_conf_init_value(ecf->accept_mutex, 1);
+    ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500);
 
     return NGX_CONF_OK;
 }
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -65,6 +65,7 @@ struct ngx_event_s {
     unsigned char    write:1;
 
     /* used to detect the stale events in kqueue, rt signals and epoll */
+    unsigned char    use_instance:1;
     unsigned char    instance:1;
     unsigned char    returned_instance:1;
 
@@ -79,7 +80,7 @@ struct ngx_event_s {
     unsigned char    posted:1;
 
     /* the ready event; in aio mode 0 means that no operation can be posted */
-    unsigned char    ready:1;
+    unsigned short   ready:1;
 
     /* aio operation is complete */
     unsigned short   complete:1;
@@ -196,59 +197,65 @@ extern ngx_event_actions_t   ngx_event_a
  * The event filter requires to read/write the whole data -
  * select, poll, /dev/poll, kqueue, epoll.
  */
-#define NGX_USE_LEVEL_EVENT    0x00000001
+#define NGX_USE_LEVEL_EVENT      0x00000001
 
 /*
  * The event filter is deleted after a notification without an additional
  * syscall - select, poll, kqueue, epoll.
  */
-#define NGX_USE_ONESHOT_EVENT  0x00000002
+#define NGX_USE_ONESHOT_EVENT    0x00000002
 
 /*
  * The event filter notifies only the changes and an initial level -
  * kqueue, epoll.
  */
-#define NGX_USE_CLEAR_EVENT    0x00000004
+#define NGX_USE_CLEAR_EVENT      0x00000004
 
 /*
  * The event filter has kqueue features - the eof flag, errno,
  * available data, etc.
  */
-#define NGX_HAVE_KQUEUE_EVENT  0x00000008
+#define NGX_HAVE_KQUEUE_EVENT    0x00000008
 
 /*
  * The event filter supports low water mark - kqueue's NOTE_LOWAT.
  * kqueue in FreeBSD 4.1-4.2 has no NOTE_LOWAT so we need a separate flag.
  */
-#define NGX_HAVE_LOWAT_EVENT   0x00000010
+#define NGX_HAVE_LOWAT_EVENT     0x00000010
+
+/*
+ * The event filter allows to pass instance information to check stale events -
+ * kqueue, epoll, rt signals.
+ */
+#define NGX_HAVE_INSTANCE_EVENT  0x00000020
 
 /*
  * The event filter notifies only the changes (the edges)
  * but not an initial level - early epoll patches.
  */
-#define NGX_USE_EDGE_EVENT     0x00000020
+#define NGX_USE_EDGE_EVENT       0x00000040
 
 /*
  * No need to add or delete the event filters - rt signals.
  */
-#define NGX_USE_SIGIO_EVENT    0x00000040
+#define NGX_USE_SIGIO_EVENT      0x00000080
 
 /*
  * The alternative event method after the rt signals queue overflow.
  */
-#define NGX_OVERFLOW_EVENT     0x00000080
+#define NGX_OVERFLOW_EVENT       0x00000100
 
 /*
  * No need to add or delete the event filters - overlapped, aio_read,
  * aioread, io_submit.
  */
-#define NGX_USE_AIO_EVENT      0x00000100
+#define NGX_USE_AIO_EVENT        0x00000200
 
 /*
  * Need to add socket or handle only once - i/o completion port.
  * It also requires HAVE_AIO and NGX_USE_AIO_EVENT to be set.
  */
-#define NGX_USE_IOCP_EVENT     0x00000200
+#define NGX_USE_IOCP_EVENT       0x00000400
 
 
 
@@ -380,6 +387,8 @@ typedef struct {
     ngx_flag_t   multi_accept;
     ngx_flag_t   accept_mutex;
 
+    ngx_msec_t   accept_mutex_delay;
+
     u_char      *name;
 } ngx_event_conf_t;
 
@@ -395,14 +404,11 @@ typedef struct {
 
 
 
-extern ngx_thread_volatile ngx_event_t  *ngx_posted_events;
-#if (NGX_THREADS)
-extern ngx_mutex_t           *ngx_posted_events_mutex;
-#endif
-
 extern ngx_atomic_t          *ngx_accept_mutex_ptr;
 extern ngx_atomic_t          *ngx_accept_mutex;
 extern ngx_uint_t             ngx_accept_mutex_held;
+extern ngx_msec_t             ngx_accept_mutex_delay;
+
 
 #define ngx_accept_mutex_unlock()                                             \
            if (ngx_accept_mutex_held) {                                       \
@@ -437,6 +443,7 @@ int ngx_event_post_acceptex(ngx_listenin
 
 
 #include <ngx_event_timer.h>
+#include <ngx_event_posted.h>
 #include <ngx_event_busy_lock.h>
 
 #if (WIN32)
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -218,11 +218,15 @@ void ngx_event_accept(ngx_event_t *ev)
         c->sockaddr = sa;
         c->socklen = len;
 
-        rev->instance = (u_char) !instance;
-        rev->returned_instance = (u_char) rinstance;
+        if (ngx_event_flags & NGX_HAVE_INSTANCE_EVENT) {
+            rev->use_instance = 1;
+            rev->instance = (u_char) !instance;
+            rev->returned_instance = (u_char) rinstance;
 
-        wev->instance = (u_char) !instance;
-        wev->returned_instance = (u_char) winstance;
+            wev->use_instance = 1;
+            wev->instance = (u_char) !instance;
+            wev->returned_instance = (u_char) winstance;
+        }
 
         rev->index = NGX_INVALID_INDEX;
         wev->index = NGX_INVALID_INDEX;
@@ -302,7 +306,9 @@ void ngx_event_accept(ngx_event_t *ev)
 
 ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
 {
-    if (*ngx_accept_mutex == 0 && ngx_atomic_cmp_set(ngx_accept_mutex, 0, 1)) {
+    if (*ngx_accept_mutex == 0
+        && ngx_atomic_cmp_set(ngx_accept_mutex, 0, ngx_pid))
+    {
 
         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                        "accept mutex locked");
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -11,7 +11,7 @@
 int ngx_event_connect_peer(ngx_peer_connection_t *pc)
 {
     int                  rc;
-    ngx_uint_t           instance;
+    ngx_uint_t           instance, rinstance, winstance;
     u_int                event;
     time_t               now;
     ngx_err_t            err;
@@ -156,11 +156,23 @@ int ngx_event_connect_peer(ngx_peer_conn
 #endif
 
     instance = rev->instance;
+    rinstance = rev->returned_instance;
+    winstance = wev->returned_instance;
 
     ngx_memzero(c, sizeof(ngx_connection_t));
     ngx_memzero(rev, sizeof(ngx_event_t));
     ngx_memzero(wev, sizeof(ngx_event_t));
 
+    if (ngx_event_flags & NGX_HAVE_INSTANCE_EVENT) {
+        rev->use_instance = 1;
+        rev->instance = (u_char) !instance;
+        rev->returned_instance = (u_char) rinstance;
+
+        wev->use_instance = 1;
+        wev->instance = (u_char) !instance;
+        wev->returned_instance = (u_char) winstance;
+    }
+
     rev->index = NGX_INVALID_INDEX;
     wev->index = NGX_INVALID_INDEX;
 
@@ -171,9 +183,6 @@ int ngx_event_connect_peer(ngx_peer_conn
     c->write = wev;
     wev->write = 1;
 
-    rev->instance = (u_char) !instance;
-    wev->instance = (u_char) !instance;
-
     c->log = pc->log;
     rev->log = pc->log;
     wev->log = pc->log;
new file mode 100644
--- /dev/null
+++ b/src/event/ngx_event_posted.c
@@ -0,0 +1,76 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ngx_thread_volatile ngx_event_t  *ngx_posted_events;
+#if (NGX_THREADS)
+ngx_mutex_t                      *ngx_posted_events_mutex;
+#endif
+
+
+void ngx_event_process_posted(ngx_cycle_t *cycle)
+{
+    ngx_event_t  *ev;
+
+    for ( ;; ) {
+
+        ev = (ngx_event_t *) ngx_posted_events;
+
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                      "posted event " PTR_FMT, ev);
+
+        if (ev == NULL) {
+            return;
+        }
+
+        ngx_posted_events = ev->next;
+
+        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, cycle->log, 0,
+                          "stale posted event " PTR_FMT, ev);
+            continue;
+        }
+
+        if (ev->posted) {
+            ev->posted = 0;
+        }
+
+        ev->event_handler(ev);
+    }
+}
+
+
+#if (NGX_THREADS)
+
+void ngx_event_thread_handler(ngx_event_t *ev)
+{
+    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);
+        return;
+    }
+
+    if (ev->posted) {
+        ev->posted = 0;
+    }
+
+    ev->event_handler(ev);
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/src/event/ngx_event_posted.h
@@ -0,0 +1,28 @@
+#ifndef _NGX_EVENT_POSTED_H_INCLUDED_
+#define _NGX_EVENT_POSTED_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#define ngx_post_event(ev)                                                    \
+                ev->next = (ngx_event_t *) ngx_posted_events;                 \
+                ngx_posted_events = ev;                                       \
+                ev->posted = 1;
+
+
+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;
+#if (NGX_THREADS)
+extern ngx_mutex_t                      *ngx_posted_events_mutex;
+#endif
+
+
+#endif /* _NGX_EVENT_POSTED_H_INCLUDED_ */
--- a/src/event/ngx_event_timer.c
+++ b/src/event/ngx_event_timer.c
@@ -42,18 +42,14 @@ ngx_msec_t ngx_event_find_timer(void)
         return 0;
     }
 
-#if (NGX_THREADS)
     if (ngx_mutex_lock(ngx_event_timer_mutex) == NGX_ERROR) {
         return NGX_TIMER_ERROR;
     }
-#endif
 
     node = ngx_rbtree_min((ngx_rbtree_t *) ngx_event_timer_rbtree,
                           &ngx_event_timer_sentinel);
 
-#if (NGX_THREADS)
     ngx_mutex_unlock(ngx_event_timer_mutex);
-#endif
 
     return (ngx_msec_t)
          (node->key * NGX_TIMER_RESOLUTION -
@@ -75,18 +71,14 @@ void ngx_event_expire_timers(ngx_msec_t 
             break;
         }
 
-#if (NGX_THREADS)
         if (ngx_mutex_lock(ngx_event_timer_mutex) == NGX_ERROR) {
             return;
         }
-#endif
 
         node = ngx_rbtree_min((ngx_rbtree_t *) ngx_event_timer_rbtree,
                               &ngx_event_timer_sentinel);
 
-#if (NGX_THREADS)
         ngx_mutex_unlock(ngx_event_timer_mutex);
-#endif
 
         if ((ngx_msec_t) node->key <= (ngx_msec_t)
                          (ngx_old_elapsed_msec + timer) / NGX_TIMER_RESOLUTION)
@@ -106,9 +98,16 @@ void ngx_event_expire_timers(ngx_msec_t 
                 ev->timedout = 1;
             }
 
-#if (NGX_THREADS)
-            /* STUB: post event */
-#endif
+            if (ngx_threaded) {
+                if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+                    return;
+                }
+
+                ngx_post_event(ev);
+
+                ngx_mutex_unlock(ngx_posted_events_mutex);
+                continue;
+            }
 
             ev->event_handler(ev);
             continue;
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -369,6 +369,9 @@ static int ngx_http_proxy_handler(ngx_ht
 
 void ngx_http_proxy_check_broken_connection(ngx_event_t *ev)
 {
+    int                    n;
+    char                   buf[1];
+    ngx_err_t              err;
     ngx_connection_t      *c;
     ngx_http_request_t    *r;
     ngx_http_proxy_ctx_t  *p;
@@ -376,15 +379,18 @@ void ngx_http_proxy_check_broken_connect
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
                    "http proxy check client, write event:%d", ev->write);
 
-    c = ev->data;
-    r = c->data;
-    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-
 #if (HAVE_KQUEUE)
 
-    /* TODO: KEVENT_EVENT */
+    if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
 
-    if (ev->kq_eof) {
+        if (!ev->kq_eof) {
+            return;
+        }
+
+        c = ev->data;
+        r = c->data;
+        p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
         ev->eof = 1;
 
         if (ev->kq_errno) {
@@ -407,17 +413,31 @@ void ngx_http_proxy_check_broken_connect
         if (p->upstream == NULL || p->upstream->peer.connection == NULL) {
             ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
         }
+
+        return;
     }
 
-#else
+#endif
+
+    c = ev->data;
+    r = c->data;
+    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     n = recv(c->fd, buf, 1, MSG_PEEK);
 
     if (n > 0) {
-        /* TODO: delete level */
+        if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
+            if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+                ngx_http_proxy_finalize_request(p,
+                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
+            }
+        }
+
         return;
     }
 
+    ev->eof = 1;
+
     if (n == -1) {
         err = ngx_socket_errno;
         if (err == NGX_EAGAIN) {
@@ -426,9 +446,9 @@ void ngx_http_proxy_check_broken_connect
 
         ev->error = 1;
 
-    } else if (n == 0) {
+    } else {
+        /* n == 0 */
         err = 0;
-        ev->eof = 1;
     }
 
     if (!p->cachable && p->upstream->peer.connection) {
@@ -439,14 +459,12 @@ void ngx_http_proxy_check_broken_connect
         return;
     }
 
-    ngx_log_error(NGX_LOG_INFO, ev->log, ev->err,
+    ngx_log_error(NGX_LOG_INFO, ev->log, err,
                   "client have closed prematurely connection");
 
     if (p->upstream == NULL || p->upstream->peer.connection == NULL) {
         ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
     }
-
-#endif
 }
 
 
@@ -870,8 +888,15 @@ static char *ngx_http_proxy_merge_loc_co
 
     ngx_conf_merge_size_value(conf->header_buffer_size,
                               prev->header_buffer_size, 4096);
+
     ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 8, 4096);
 
+    if (conf->bufs.num < 2) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "there must be at least 2 \"proxy_buffers\"");
+        return NGX_CONF_ERROR;
+    }
+
     size = conf->header_buffer_size;
     if (size < conf->bufs.size) {
         size = conf->bufs.size;
@@ -891,6 +916,14 @@ static char *ngx_http_proxy_merge_loc_co
              "one of the \"proxy_buffers\"");
 
         return NGX_CONF_ERROR;
+
+    } else if (conf->busy_buffers_size > (conf->bufs.num - 1) * conf->bufs.size)
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"proxy_busy_buffers_size\" must be less than "
+             "the size of all \"proxy_buffers\" minus one buffer");
+
+        return NGX_CONF_ERROR;
     }
 
 
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event.h>
 
 
 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
@@ -142,6 +143,18 @@ void ngx_process_get_status()
             return;
         }
 
+
+        if (ngx_accept_mutex_ptr) {
+
+            /*
+             * unlock the accept mutex if the abnormally exited process
+             * held it
+             */
+
+            ngx_atomic_cmp_set(ngx_accept_mutex_ptr, pid, 0);
+        }
+
+
         one = 1;
         process = "";
 
--- a/src/os/win32/ngx_process_cycle.c
+++ b/src/os/win32/ngx_process_cycle.c
@@ -16,6 +16,8 @@ sig_atomic_t  ngx_timer;
 
 #endif
 
+ngx_int_t     ngx_threaded;
+
 sig_atomic_t  ngx_terminate;
 sig_atomic_t  ngx_quit;