changeset 354:eaf1f651cf86

nginx-0.0.7-2004-06-15-11:55:11 import
author Igor Sysoev <igor@sysoev.ru>
date Tue, 15 Jun 2004 07:55:11 +0000
parents b8d3d7dbfcc8
children 0fb6c53fb135
files auto/os/freebsd auto/os/linux src/core/nginx.h src/core/ngx_core.h src/core/ngx_palloc.h src/event/modules/ngx_rtsig_module.c src/event/ngx_event.c src/event/ngx_event.h src/os/unix/ngx_posix_init.c src/os/unix/ngx_process.c src/os/unix/ngx_process.h src/os/unix/ngx_process_cycle.c src/os/unix/ngx_process_cycle.h src/os/unix/ngx_socket.c
diffstat 14 files changed, 424 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/auto/os/freebsd
+++ b/auto/os/freebsd
@@ -66,3 +66,6 @@ if [ $EVENT_AIO = YES ]; then
 else
     have=HAVE_AIO . auto/nohave
 fi
+
+
+have=HAVE_MSGHDR_MSG_CONTROL . auto/have
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -77,3 +77,6 @@ ngx_func_test="prctl(PR_SET_DUMPABLE, 1,
 if [ $ngx_found = yes ]; then
     have=HAVE_PR_SET_DUMPABLE . auto/have
 fi
+
+
+have=HAVE_MSGHDR_MSG_CONTROL . auto/have
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -2,7 +2,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.0.5"
+#define NGINX_VER          "nginx/0.0.7"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_NEWPID_EXT     ".newbin"
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -5,11 +5,11 @@
 typedef struct ngx_module_s      ngx_module_t;
 typedef struct ngx_conf_s        ngx_conf_t;
 typedef struct ngx_cycle_s       ngx_cycle_t;
+typedef struct ngx_pool_s        ngx_pool_t;
 typedef struct ngx_log_s         ngx_log_t;
 typedef struct ngx_array_s       ngx_array_t;
 typedef struct ngx_open_file_s   ngx_open_file_t;
 typedef struct ngx_command_s     ngx_command_t;
-
 typedef struct ngx_file_s        ngx_file_t;
 typedef struct ngx_event_s       ngx_event_t;
 typedef struct ngx_connection_s  ngx_connection_t;
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -26,8 +26,6 @@ struct ngx_pool_large_s {
 };
 
 
-typedef struct ngx_pool_s        ngx_pool_t;
-
 struct ngx_pool_s {
     char              *last;
     char              *end;
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -177,6 +177,10 @@ static ngx_int_t ngx_rtsig_add_connectio
     ngx_rtsig_conf_t  *rtscf;
 
     if (c->read->accept && c->read->disabled) {
+
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                       "rtsig enable connection: fd:%d", c->fd);
+
         if (fcntl(c->fd, F_SETOWN, ngx_pid) == -1) {
             ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
                           "fcntl(F_SETOWN) failed");
@@ -233,14 +237,20 @@ static ngx_int_t ngx_rtsig_del_connectio
                    "rtsig del connection: fd:%d", c->fd);
 
     if ((flags & NGX_DISABLE_EVENT) && c->read->accept) {
+
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                       "rtsig disable connection: fd:%d", c->fd);
+
         c->read->active = 0;
-        c->read->disabled = 0;
+        c->read->disabled = 1;
         return NGX_OK;
     }
 
     if (flags & NGX_CLOSE_EVENT) {
         c->read->active = 0;
         c->write->active = 0;
+        c->read->posted = 0;
+        c->write->posted = 0;
         return NGX_OK;
     }
 
@@ -252,6 +262,8 @@ static ngx_int_t ngx_rtsig_del_connectio
 
     c->read->active = 0;
     c->write->active = 0;
+    c->read->posted = 0;
+    c->write->posted = 0;
 
     return NGX_OK;
 }
@@ -299,6 +311,8 @@ ngx_int_t ngx_rtsig_process_events(ngx_c
                 ngx_accept_disabled--;
 
             } else {
+                ngx_accept_mutex_held = 0;
+
                 if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
                     return NGX_ERROR;
                 }
@@ -517,7 +531,8 @@ ngx_int_t ngx_rtsig_process_events(ngx_c
 
 static ngx_int_t ngx_rtsig_process_overflow(ngx_cycle_t *cycle)
 {
-    int                name[2], len, rtsig_max, rtsig_nr, events, ready;
+    int                name[2], rtsig_max, rtsig_nr, events, ready;
+    size_t             len;
     ngx_int_t          tested, n, i;
     ngx_err_t          err;
     ngx_connection_t  *c;
@@ -709,8 +724,8 @@ static char *ngx_rtsig_init_conf(ngx_cyc
     ngx_conf_init_value(rtscf->signo, SIGRTMIN + 10);
 
     ngx_conf_init_value(rtscf->overflow_events, 16);
-    ngx_conf_init_value(rtscf->overflow_test, 100);
-    ngx_conf_init_value(rtscf->overflow_threshold, 4);
+    ngx_conf_init_value(rtscf->overflow_test, 32);
+    ngx_conf_init_value(rtscf->overflow_threshold, 10);
 
     return NGX_CONF_OK;
 }
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -628,7 +628,7 @@ static void *ngx_event_create_conf(ngx_c
 
 static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf)
 {
-    ngx_event_conf_t *ecf = conf;
+    ngx_event_conf_t  *ecf = conf;
 
 #if (HAVE_KQUEUE)
 
@@ -650,6 +650,8 @@ static char *ngx_event_init_conf(ngx_cyc
 
 #elif (HAVE_RTSIG)
 
+    ngx_core_conf_t  *ccf;
+
     ngx_conf_init_unsigned_value(ecf->connections, DEFAULT_CONNECTIONS);
     ngx_conf_init_value(ecf->use, ngx_rtsig_module.ctx_index);
     ngx_conf_init_ptr_value(ecf->name, ngx_rtsig_module_ctx.name->data);
@@ -701,5 +703,18 @@ static char *ngx_event_init_conf(ngx_cyc
     ngx_conf_init_value(ecf->accept_mutex, 1);
     ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500);
 
+#if (HAVE_RTSIG)
+    if (ecf->use == ngx_rtsig_module.ctx_index && ecf->accept_mutex == 0) {
+        ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
+                                               ngx_core_module);
+        if (ccf->worker_processes) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+                          "the \"rtsig\" method requires "
+                          "\"accept_mutex\" to be on");
+            return NGX_CONF_ERROR;
+        }
+    }
+#endif
+
     return NGX_CONF_OK;
 }
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -277,11 +277,11 @@ extern ngx_event_actions_t   ngx_event_a
  */
 
 #define NGX_CLOSE_EVENT    1
+#define NGX_DISABLE_EVENT  2
 
 
 /* these flags have a meaning only for kqueue */
 #define NGX_LOWAT_EVENT    0
-#define NGX_DISABLE_EVENT  0
 #define NGX_VNODE_EVENT    0
 
 
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -46,6 +46,8 @@ ngx_signal_t  signals[] = {
 
     { SIGINT, "SIGINT", ngx_signal_handler },
 
+    { SIGIO, "SIGIO", ngx_signal_handler },
+
     { SIGCHLD, "SIGCHLD", ngx_signal_handler },
 
     { SIGPIPE, "SIGPIPE, SIG_IGN", SIG_IGN },
@@ -172,11 +174,15 @@ void ngx_signal_handler(int signo)
         case SIGALRM:
             if (!ngx_terminate) {
                 ngx_timer = 1;
-                action = ", shutting down old worker process";
+                action = ", shutting down old worker processes";
             }
 
             break;
 
+        case SIGIO:
+            ngx_sigio = 1;
+            break;
+
         case SIGCHLD:
             ngx_reap = 1;
             break;
@@ -206,6 +212,7 @@ void ngx_signal_handler(int signo)
         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
+        case SIGIO:
             action = ", ignoring";
             break;
         }
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -6,7 +6,8 @@
 
 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
 
-ngx_uint_t     ngx_last_process;
+ngx_int_t      ngx_last_process;
+ngx_socket_t   ngx_channel;
 ngx_process_t  ngx_processes[NGX_MAX_PROCESSES];
 
 
@@ -14,17 +15,44 @@ ngx_pid_t ngx_spawn_process(ngx_cycle_t 
                             ngx_spawn_proc_pt proc, void *data,
                             char *name, ngx_int_t respawn)
 {
+    u_long     on;
     ngx_pid_t  pid;
+    ngx_int_t  s;
+
+    s = respawn >= 0 ? respawn : ngx_last_process;
+
+
+    /* Solaris 9 still has no AF_LOCAL */
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                      "socketpair() failed while spawning \"%s\"", name);
+        return NGX_ERROR;
+    }
+
+    on = 1;
+    if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                      "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
+        return NGX_ERROR;
+    }
+
+    if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                      "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
+        return NGX_ERROR;
+    }
+
+    ngx_channel = ngx_processes[s].channel[1];
+
 
     pid = fork();
 
-    if (pid == -1) {
+    switch (pid) {
+
+    case -1:
         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                       "fork() failed while spawning \"%s\"", name);
-    }
-
-    switch (pid) {
-    case -1:
         return NGX_ERROR;
 
     case 0:
@@ -39,37 +67,36 @@ ngx_pid_t ngx_spawn_process(ngx_cycle_t 
     ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                    "spawn %s: " PID_T_FMT, name, pid);
 
+    ngx_processes[s].pid = pid;
+    ngx_processes[s].exited = 0;
+
     if (respawn >= 0) {
-        ngx_processes[respawn].pid = pid;
-        ngx_processes[respawn].exited = 0;
         return pid;
     }
 
-    ngx_processes[ngx_last_process].pid = pid;
-    ngx_processes[ngx_last_process].proc = proc;
-    ngx_processes[ngx_last_process].data = data;
-    ngx_processes[ngx_last_process].name = name;
-    ngx_processes[ngx_last_process].exited = 0;
-    ngx_processes[ngx_last_process].exiting = 0;
+    ngx_processes[s].proc = proc;
+    ngx_processes[s].data = data;
+    ngx_processes[s].name = name;
+    ngx_processes[s].exiting = 0;
 
     switch (respawn) {
 
     case NGX_PROCESS_RESPAWN:
-        ngx_processes[ngx_last_process].respawn = 1;
-        ngx_processes[ngx_last_process].just_respawn = 0;
-        ngx_processes[ngx_last_process].detached = 0;
+        ngx_processes[s].respawn = 1;
+        ngx_processes[s].just_respawn = 0;
+        ngx_processes[s].detached = 0;
         break;
 
     case NGX_PROCESS_JUST_RESPAWN:
-        ngx_processes[ngx_last_process].respawn = 1;
-        ngx_processes[ngx_last_process].just_respawn = 1;
-        ngx_processes[ngx_last_process].detached = 0;
+        ngx_processes[s].respawn = 1;
+        ngx_processes[s].just_respawn = 1;
+        ngx_processes[s].detached = 0;
         break;
 
     case NGX_PROCESS_DETACHED:
-        ngx_processes[ngx_last_process].respawn = 0;
-        ngx_processes[ngx_last_process].just_respawn = 0;
-        ngx_processes[ngx_last_process].detached = 1;
+        ngx_processes[s].respawn = 0;
+        ngx_processes[s].just_respawn = 0;
+        ngx_processes[s].detached = 1;
         break;
     }
 
@@ -106,7 +133,8 @@ void ngx_process_get_status()
     char            *process;
     ngx_pid_t        pid;
     ngx_err_t        err;
-    ngx_uint_t       i, one;
+    ngx_int_t        i;
+    ngx_uint_t       one;
     struct timeval   tv;
     one = 0;
 
--- a/src/os/unix/ngx_process.h
+++ b/src/os/unix/ngx_process.h
@@ -9,6 +9,7 @@ typedef void (*ngx_spawn_proc_pt) (ngx_c
 typedef struct {
     ngx_pid_t           pid;
     int                 status;
+    ngx_socket_t        channel[2];
 
     ngx_spawn_proc_pt   proc;
     void               *data;
@@ -48,7 +49,8 @@ ngx_pid_t ngx_execute(ngx_cycle_t *cycle
 void ngx_process_get_status(void);
 
 extern ngx_pid_t      ngx_pid;
-extern ngx_uint_t     ngx_last_process;
+extern ngx_int_t      ngx_last_process;
+extern ngx_socket_t   ngx_channel;
 extern ngx_process_t  ngx_processes[NGX_MAX_PROCESSES];
 
 
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -11,6 +11,7 @@ static void ngx_start_worker_processes(n
 static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo);
 static void ngx_master_exit(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx);
 static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data);
+static void ngx_channel_handler(ngx_event_t *ev);
 #if (NGX_THREADS)
 static int ngx_worker_thread_cycle(void *data);
 #endif
@@ -22,6 +23,7 @@ ngx_uint_t    ngx_threaded;
 
 sig_atomic_t  ngx_reap;
 sig_atomic_t  ngx_timer;
+sig_atomic_t  ngx_sigio;
 sig_atomic_t  ngx_terminate;
 sig_atomic_t  ngx_quit;
 ngx_uint_t    ngx_exiting;
@@ -45,8 +47,7 @@ void ngx_master_process_cycle(ngx_cycle_
     char              *title;
     u_char            *p;
     size_t             size;
-    ngx_int_t          n;
-    ngx_uint_t         i;
+    ngx_int_t          n, i;
     sigset_t           set;
     struct timeval     tv;
     struct itimerval   itv;
@@ -57,6 +58,7 @@ void ngx_master_process_cycle(ngx_cycle_
     sigemptyset(&set);
     sigaddset(&set, SIGCHLD);
     sigaddset(&set, SIGALRM);
+    sigaddset(&set, SIGIO);
     sigaddset(&set, SIGINT);
     sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
     sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
@@ -360,8 +362,31 @@ static void ngx_start_worker_processes(n
 
 static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo)
 {
-    ngx_uint_t  i;
-    ngx_err_t   err;
+    ngx_int_t      i;
+    ngx_err_t      err;
+    ngx_channel_t  ch;
+
+
+    switch (signo) {
+
+    case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
+        ch.command = NGX_CMD_QUIT;
+        break;
+
+    case ngx_signal_value(NGX_TERMINATE_SIGNAL):
+        ch.command = NGX_CMD_TERMINATE;
+        break;
+
+    case ngx_signal_value(NGX_REOPEN_SIGNAL):
+        ch.command = NGX_CMD_REOPEN;
+        break;
+
+    default:
+        ch.command = 0;
+    }
+
+    ch.fd = -1;
+
 
     for (i = 0; i < ngx_last_process; i++) {
 
@@ -380,6 +405,18 @@ static void ngx_signal_worker_processes(
             continue;
         }
 
+        if (ch.command) {
+            if (ngx_write_channel(ngx_processes[i].channel[0],
+                           &ch, sizeof(ngx_channel_t), cycle->log) == NGX_OK)
+            {
+                if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) {
+                    ngx_processes[i].exiting = 1;
+                }
+
+                continue;
+            }
+        }
+
         ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                        "kill (" PID_T_FMT ", %d)" ,
                        ngx_processes[i].pid, signo);
@@ -420,21 +457,22 @@ static void ngx_master_exit(ngx_cycle_t 
 
 static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
 {
-    sigset_t          set;
-    ngx_uint_t        i;
-    ngx_listening_t  *ls;
-    ngx_core_conf_t  *ccf;
+    sigset_t           set;
+    ngx_int_t          n;
+    ngx_uint_t         i;
+    ngx_listening_t   *ls;
+    ngx_core_conf_t   *ccf;
+    ngx_connection_t  *c;
 #if (NGX_THREADS)
-    ngx_tid_t         tid;
+    ngx_tid_t          tid;
 #endif
 
     ngx_process = NGX_PROCESS_WORKER;
-    ngx_last_process = 0;
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
     if (ccf->group != (gid_t) NGX_CONF_UNSET) {
-        if (setuid(ccf->group) == -1) {
+        if (setgid(ccf->group) == -1) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                           "setgid(%d) failed", ccf->group);
             /* fatal */
@@ -442,7 +480,7 @@ static void ngx_worker_process_cycle(ngx
         }
     }
 
-    if (ccf->user != (uid_t) NGX_CONF_UNSET && geteuid() == 0) {
+    if (ccf->user != (uid_t) NGX_CONF_UNSET) {
         if (setuid(ccf->user) == -1) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                           "setuid(%d) failed", ccf->user);
@@ -489,6 +527,59 @@ static void ngx_worker_process_cycle(ngx
         }
     }
 
+    for (n = 0; n < ngx_last_process; n++) {
+
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+                       "close channel %d", ngx_processes[n].channel[1]);
+
+        if (close(ngx_processes[n].channel[1]) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          "close() failed");
+        }
+    }
+
+    if (close(ngx_processes[ngx_last_process].channel[0]) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                      "close() failed");
+    }
+
+#if 0
+    ngx_last_process = 0;
+#endif
+
+    c = &cycle->connections[ngx_channel];
+    ngx_memzero(c, sizeof(ngx_connection_t));
+
+    c->fd = ngx_channel;
+    c->pool = cycle->pool;
+    c->read = &cycle->read_events[ngx_channel];
+    c->write = &cycle->write_events[ngx_channel];
+
+    ngx_memzero(c->read, sizeof(ngx_event_t));
+    ngx_memzero(c->write, sizeof(ngx_event_t));
+
+    c->log = cycle->log;
+    c->read->log = cycle->log;
+    c->write->log = cycle->log;
+    c->read->index = NGX_INVALID_INDEX;
+    c->write->index = NGX_INVALID_INDEX;
+    c->read->data = c;
+    c->write->data = c;
+    c->read->event_handler = ngx_channel_handler;
+
+    if (ngx_add_conn) {
+        if (ngx_add_conn(c) == NGX_ERROR) {
+            /* fatal */
+            exit(2);
+        }
+
+    } else {
+        if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) {
+            /* fatal */
+            exit(2);
+        }
+    }
+
     ngx_setproctitle("worker process");
 
 #if (NGX_THREADS)
@@ -555,6 +646,37 @@ static void ngx_worker_process_cycle(ngx
 }
 
 
+static void ngx_channel_handler(ngx_event_t *ev)
+{
+    ngx_int_t          n;
+    ngx_channel_t      ch;
+    ngx_connection_t  *c;
+
+    c = ev->data;
+
+    n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);
+
+    if (n <= 0) {
+        return;
+    }
+
+    switch (ch.command) {
+
+    case NGX_CMD_QUIT:
+        ngx_quit = 1;
+        break;
+
+    case NGX_CMD_TERMINATE:
+        ngx_terminate = 1;
+        break;
+
+    case NGX_CMD_REOPEN:
+        ngx_reopen = 1;
+        break;
+    }
+}
+
+
 #if (NGX_THREADS)
 
 int ngx_worker_thread_cycle(void *data)
@@ -597,3 +719,159 @@ int ngx_worker_thread_cycle(void *data)
 }
 
 #endif
+
+
+ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
+                            ngx_log_t *log) 
+{
+    ssize_t          n;
+    ngx_err_t        err;
+    struct iovec     iov[1];
+    struct msghdr    msg;
+    struct cmsghdr   cm;
+
+#if (HAVE_MSGHDR_MSG_CONTROL)
+
+    if (ch->fd == -1) {
+        msg.msg_control = NULL;
+        msg.msg_controllen = 0;
+
+    } else {
+        msg.msg_control = &cm;
+        msg.msg_controllen = sizeof(struct cmsghdr) +  sizeof(int);
+
+        cm.cmsg_len = sizeof(struct cmsghdr) +  sizeof(int);
+        cm.cmsg_level = SOL_SOCKET; 
+        cm.cmsg_type = SCM_RIGHTS;
+        *((int *) ((char *) &cm + sizeof(struct cmsghdr))) = ch->fd;
+    }
+
+#else
+
+    if (ch->fd == -1) {
+        msg.msg_accrights = NULL;
+        msg.msg_accrightslen = 0;
+
+    } else {
+        msg.msg_accrights = (caddr_t) &ch->fd;
+        msg.msg_accrightslen = sizeof(int);
+    }
+
+#endif
+
+    iov[0].iov_base = (char *) ch;
+    iov[0].iov_len = size;
+
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+
+    n = sendmsg(s, &msg, MSG_DONTWAIT);
+
+    if (n == -1) {
+        err = ngx_errno;
+        if (err == NGX_EAGAIN) {
+            return NGX_AGAIN;
+        }
+
+        ngx_log_error(NGX_LOG_ALERT, log, err, "sendmsg() failed");
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
+                           ngx_log_t *log)
+{   
+    int              fd;
+    ssize_t          n;
+    ngx_err_t        err;
+    struct iovec     iov[1];
+    struct msghdr    msg;
+    struct cmsghdr  *cm;
+
+    iov[0].iov_base = (char *) ch;
+    iov[0].iov_len = size;
+
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+
+#if (HAVE_MSGHDR_MSG_CONTROL)
+    msg.msg_control = &cm;
+    msg.msg_controllen = sizeof(struct cmsghdr) +  sizeof(int);
+#else
+    msg.msg_accrights = (caddr_t) &fd;
+    msg.msg_accrightslen = sizeof(int);
+#endif
+
+    n = recvmsg(s, &msg, MSG_DONTWAIT);
+
+    if (n == -1) {
+        err = ngx_errno;
+        if (err == NGX_EAGAIN) {
+            return NGX_AGAIN;
+        }
+
+        ngx_log_error(NGX_LOG_ALERT, log, err, "recvmsg() failed");
+        return NGX_ERROR;
+    }
+
+    if ((size_t) n < sizeof(ngx_channel_t)) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0,
+                      "recvmsg() returned not enough data");
+        return NGX_ERROR;
+    }
+
+#if (HAVE_MSGHDR_MSG_CONTROL)
+
+    if (ch->command == NGX_CMD_OPEN_CHANNEL) {
+        cm = msg.msg_control;
+
+        if (cm == NULL) {
+            ngx_log_error(NGX_LOG_ALERT, log, 0, 
+                          "recvmsg() returned no ancillary data");
+            return NGX_ERROR;
+        }
+
+        if (cm->cmsg_len < sizeof(struct cmsghdr) + sizeof(int)) {
+            ngx_log_error(NGX_LOG_ALERT, log, 0,
+                          "recvmsg() returned too small ancillary data");
+            return NGX_ERROR;
+        }
+
+        if (cm->cmsg_level != SOL_SOCKET || cm->cmsg_type != SCM_RIGHTS) {
+            ngx_log_error(NGX_LOG_ALERT, log, 0,
+                          "recvmsg() returned invalid ancillary data "
+                          "level %d or type %d", cm->cmsg_level, cm->cmsg_type);
+            return NGX_ERROR;
+        }
+
+        ch->fd = *((int *) ((char *) cm + sizeof(struct cmsghdr)));
+    }
+
+    if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0,
+                      "recvmsg() truncated data");
+    }
+
+#else
+
+    if (ch->command == NGX_CMD_OPEN_CHANNEL) {
+        if (msg.msg_accrightslen != sizeof(int)) {
+            ngx_log_error(NGX_LOG_ALERT, log, 0, 
+                          "recvmsg() returned no ancillary data");
+            return NGX_ERROR;
+        }
+
+        ch->fd = fd;
+    }
+
+#endif
+
+    return n;
+}
--- a/src/os/unix/ngx_process_cycle.h
+++ b/src/os/unix/ngx_process_cycle.h
@@ -6,6 +6,20 @@
 #include <ngx_core.h>
 
 
+#define NGX_CMD_OPEN_CHANNEL   1
+#define NGX_CMD_CLOSE_CHANNEL  2
+#define NGX_CMD_QUIT           3
+#define NGX_CMD_TERMINATE      4
+#define NGX_CMD_REOPEN         5
+
+
+typedef struct {
+     ngx_uint_t  command;
+     ngx_pid_t   pid;
+     ngx_fd_t    fd;
+} ngx_channel_t;
+
+
 typedef struct {
      int           argc;
      char *const  *argv;
@@ -21,6 +35,12 @@ void ngx_master_process_cycle(ngx_cycle_
 void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx);
 
 
+ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
+                            ngx_log_t *log);
+ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
+                           ngx_log_t *log);
+
+
 extern ngx_uint_t      ngx_process;
 extern ngx_pid_t       ngx_pid;
 extern ngx_pid_t       ngx_new_binary;
@@ -30,6 +50,7 @@ extern ngx_uint_t      ngx_exiting;
 
 extern sig_atomic_t    ngx_reap;
 extern sig_atomic_t    ngx_timer;
+extern sig_atomic_t    ngx_sigio;
 extern sig_atomic_t    ngx_quit;
 extern sig_atomic_t    ngx_terminate;
 extern sig_atomic_t    ngx_noaccept;
--- a/src/os/unix/ngx_socket.c
+++ b/src/os/unix/ngx_socket.c
@@ -19,7 +19,9 @@
 
 int ngx_nonblocking(ngx_socket_t s)
 {
-    unsigned long  nb = 1;
+    u_long  nb;
+
+    nb = 1;
 
     return ioctl(s, FIONBIO, &nb);
 }
@@ -27,7 +29,9 @@ int ngx_nonblocking(ngx_socket_t s)
 
 int ngx_blocking(ngx_socket_t s)
 {
-    unsigned long  nb = 0;
+    u_long  nb;
+
+    nb = 0;
 
     return ioctl(s, FIONBIO, &nb);
 }