changeset 571:458b6c3fea65 release-0.3.7

nginx-0.3.7-RELEASE import *) Feature: the "access_log" supports the "buffer=" parameter. *) Bugfix: nginx could not be built on platforms different from i386, amd64, sparc, and ppc; the bug had appeared in 0.3.2.
author Igor Sysoev <igor@sysoev.ru>
date Thu, 27 Oct 2005 15:46:13 +0000
parents 2cdf120d8970
children ae8920455206
files auto/threads docs/xml/nginx/changes.xml src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/core/ngx_cycle.c src/core/ngx_log.c src/event/ngx_event_openssl.c src/http/modules/ngx_http_log_module.c src/http/ngx_http_variables.c src/imap/ngx_imap.h src/imap/ngx_imap_proxy_module.c src/os/unix/ngx_atomic.h src/os/unix/ngx_files.h src/os/unix/ngx_process_cycle.c src/os/win32/ngx_files.h
diffstat 16 files changed, 250 insertions(+), 110 deletions(-) [+]
line wrap: on
line diff
--- a/auto/threads
+++ b/auto/threads
@@ -50,7 +50,7 @@ case $USE_THREADS in
                 CORE_LIBS="$CORE_LIBS -pthread"
             ;;
 
-            FreeBSD:[567]*)
+            FreeBSD:[56]*)
                 have=NGX_THREADS . auto/have
                 CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS"
                 CORE_LIBS="$CORE_LIBS -lc_r"
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -9,6 +9,31 @@
 <title lang="en">nginx changelog</title>
 
 
+<changes ver="0.3.7" date="27.10.2005">
+
+<change type="feature">
+<para lang="ru">
+директива access_log поддерживает параметр buffer=.
+</para>
+<para lang="en">
+the "access_log" supports the "buffer=" parameter.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx не собирался на платформах, отличных от i386, amd64, sparc и ppc;
+ошибка появилась в 0.3.2.
+</para>
+<para lang="en">
+nginx could not be built on platforms different from i386, amd64, sparc и ppc;
+bug appeared in 0.3.2.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.3.6" date="24.10.2005">
 
 <change type="change">
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.6"
+#define NGINX_VER          "nginx/0.3.7"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -11,6 +11,7 @@
 static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
 static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
 static char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static void ngx_conf_flush_files(ngx_cycle_t *cycle);
 
 
 static ngx_command_t  ngx_conf_commands[] = {
@@ -36,7 +37,7 @@ ngx_module_t  ngx_conf_module = {
     NULL,                                  /* init process */
     NULL,                                  /* init thread */
     NULL,                                  /* exit thread */
-    NULL,                                  /* exit process */
+    ngx_conf_flush_files,                  /* exit process */
     NULL,                                  /* exit master */
     NGX_MODULE_V1_PADDING
 };
@@ -742,10 +743,44 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n
         file->name.data = NULL;
     }
 
+    file->buffer = NULL;
+
     return file;
 }
 
 
+static void
+ngx_conf_flush_files(ngx_cycle_t *cycle)
+{
+    ngx_uint_t        i;
+    ngx_list_part_t  *part;
+    ngx_open_file_t  *file;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "flush files");
+
+    part = &cycle->open_files.part;
+    file = part->elts;
+
+    for (i = 0; /* void */ ; i++) {
+
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+            part = part->next;
+            file = part->elts;
+            i = 0;
+        }
+
+        if (file[i].buffer == NULL || file[i].pos - file[i].buffer == 0) {
+            continue;
+        }
+
+        ngx_write_fd(file[i].fd, file[i].buffer, file[i].pos - file[i].buffer);
+    }
+}
+
+
 void ngx_cdecl
 ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err,
     char *fmt, ...)
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -34,6 +34,7 @@
 
 #define NGX_CONF_TAKE23      (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
 
+#define NGX_CONF_TAKE123     (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
 #define NGX_CONF_TAKE1234    (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3   \
                               |NGX_CONF_TAKE4)
 
@@ -87,6 +88,11 @@ struct ngx_command_s {
 struct ngx_open_file_s {
     ngx_fd_t              fd;
     ngx_str_t             name;
+
+    u_char               *buffer;
+    u_char               *pos;
+    u_char               *last;
+
 #if 0
     /* e.g. append mode, error_log */
     ngx_uint_t            flags;
@@ -121,10 +127,10 @@ struct ngx_module_s {
 
     ngx_int_t           (*init_process)(ngx_cycle_t *cycle);
     ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);
-    ngx_int_t           (*exit_thread)(ngx_cycle_t *cycle);
-    ngx_int_t           (*exit_process)(ngx_cycle_t *cycle);
+    void                (*exit_thread)(ngx_cycle_t *cycle);
+    void                (*exit_process)(ngx_cycle_t *cycle);
 
-    ngx_int_t           (*exit_master)(ngx_cycle_t *cycle);
+    void                (*exit_master)(ngx_cycle_t *cycle);
 
     uintptr_t             spare_hook0;
     uintptr_t             spare_hook1;
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -724,6 +724,12 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx
             continue;
         }
 
+        if (file[i].buffer && file[i].pos - file[i].buffer != 0) {
+            ngx_write_fd(file[i].fd, file[i].buffer,
+                         file[i].pos - file[i].buffer);
+            file[i].pos = file[i].buffer;
+        }
+
         fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR,
                            NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND);
 
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -8,7 +8,6 @@
 #include <ngx_core.h>
 
 
-static void ngx_log_write(ngx_log_t *log, u_char *errstr, size_t len);
 static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
@@ -152,42 +151,13 @@ ngx_log_error_core(ngx_uint_t level, ngx
         p = log->handler(log, p, last - p);
     }
 
-    ngx_log_write(log, errstr, p - errstr);
-}
-
-
-static void
-ngx_log_write(ngx_log_t *log, u_char *errstr, size_t len)
-{
-#if (NGX_WIN32)
-    u_long  written;
-
-    if (len >= NGX_MAX_ERROR_STR - 1) {
-        len = NGX_MAX_ERROR_STR - 2;
+    if (p > last - NGX_LINEFEED_SIZE) {
+        p = last - NGX_LINEFEED_SIZE;
     }
 
-    errstr[len++] = CR;
-    errstr[len++] = LF;
-
-    WriteFile(log->file->fd, errstr, len, &written, NULL);
-
-#if 0
-    if (WriteFile(log->file->fd, errstr, len, &written, NULL) == 0) {
-        ngx_message_box("nginx", MB_OK, ngx_errno, "WriteFile() failed");
-    }
-#endif
+    ngx_linefeed(p);
 
-#else
-
-    if (len == NGX_MAX_ERROR_STR) {
-        len--;
-    }
-
-    errstr[len++] = LF;
-
-    (void) write(log->file->fd, errstr, len);
-
-#endif
+    ngx_write_fd(log->file->fd, errstr, p - errstr);
 }
 
 
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -22,6 +22,7 @@ static void ngx_ssl_connection_error(ngx
     ngx_err_t err, char *text);
 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf);
+static void ngx_openssl_exit(ngx_cycle_t *cycle);
 
 #if !(NGX_SSL_ENGINE)
 static char *ngx_openssl_noengine(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -64,7 +65,7 @@ ngx_module_t  ngx_openssl_module = {
     NULL,                                  /* init thread */
     NULL,                                  /* exit thread */
     NULL,                                  /* exit process */
-    NULL,                                  /* exit master */
+    ngx_openssl_exit,                      /* exit master */
     NGX_MODULE_V1_PADDING
 };
 
@@ -908,7 +909,7 @@ ngx_openssl_init_conf(ngx_cycle_t *cycle
 {
 #if (NGX_SSL_ENGINE)
     ngx_openssl_conf_t *oscf = conf;
-    
+
     ENGINE  *engine;
 
     if (oscf->engine.len == 0) {
@@ -951,3 +952,12 @@ ngx_openssl_noengine(ngx_conf_t *cf, ngx
 }
 
 #endif
+
+
+static void
+ngx_openssl_exit(ngx_cycle_t *cycle)
+{
+#if (NGX_SSL_ENGINE)
+    ENGINE_cleanup();
+#endif
+}
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -96,7 +96,7 @@ static ngx_command_t  ngx_http_log_comma
       NULL },
 
     { ngx_string("access_log"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
       ngx_http_log_set_log,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -190,11 +190,9 @@ ngx_http_log_handler(ngx_http_request_t 
     u_char                   *line, *p;
     size_t                    len;
     ngx_http_log_t           *log;
+    ngx_open_file_t          *file;
     ngx_http_log_op_t        *op;
     ngx_http_log_loc_conf_t  *lcf;
-#if (NGX_WIN32)
-    u_long                    written;
-#endif
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http log handler");
@@ -219,11 +217,34 @@ ngx_http_log_handler(ngx_http_request_t 
             }
         }
 
-#if (NGX_WIN32)
-        len += 2;
-#else
-        len++;
-#endif
+        len += NGX_LINEFEED_SIZE;
+
+        file = log[l].file;
+
+        if (file->buffer) {
+
+            if (len > (size_t) (file->last - file->pos)) {
+
+                ngx_write_fd(file->fd, file->buffer, file->pos - file->buffer);
+
+                file->pos = file->buffer;
+            }
+
+            if (len <= (size_t) (file->last - file->pos)) {
+
+                p = file->pos;
+
+                for (i = 0; i < log[l].ops->nelts; i++) {
+                    p = op[i].run(r, p, &op[i]);
+                }
+
+                ngx_linefeed(p);
+
+                file->pos = p;
+
+                continue;
+            }
+        }
 
         line = ngx_palloc(r->pool, len);
         if (line == NULL) {
@@ -236,13 +257,9 @@ ngx_http_log_handler(ngx_http_request_t 
             p = op[i].run(r, p, &op[i]);
         }
 
-#if (NGX_WIN32)
-        *p++ = CR; *p++ = LF;
-        WriteFile(log[l].file->fd, line, p - line, &written, NULL);
-#else
-        *p++ = LF;
-        write(log[l].file->fd, line, p - line);
-#endif
+        ngx_linefeed(p);
+
+        ngx_write_fd(file->fd, line, p - line);
     }
 
     return NGX_OK;
@@ -942,6 +959,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx
 {
     ngx_http_log_loc_conf_t *llcf = conf;
 
+    ssize_t                    buf;
     ngx_uint_t                 i;
     ngx_str_t                 *value, name;
     ngx_http_log_t            *log;
@@ -974,7 +992,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    if (cf->args->nelts == 3) {
+    if (cf->args->nelts >= 3) {
         name = value[2];
     } else {
         name.len = sizeof("combined") - 1;
@@ -987,14 +1005,51 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx
             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
         {
             log->ops = fmt[i].ops;
-            return NGX_CONF_OK;
+            goto buffer;
         }
     }
 
     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                        "unknown log format \"%V\"", &name);
+    return NGX_CONF_ERROR;
 
-    return NGX_CONF_ERROR;
+buffer:
+
+    if (cf->args->nelts == 4) {
+        if (ngx_strncmp(value[3].data, "buffer=", 7) != 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid parameter \"%V\"", &value[3]);
+            return NGX_CONF_ERROR;
+        }
+
+        name.len = value[3].len - 7;
+        name.data = value[3].data + 7;
+
+        buf = ngx_parse_size(&name);
+
+        if (buf == NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid parameter \"%V\"", &value[3]);
+            return NGX_CONF_ERROR;
+        }
+
+        if (log->file->buffer && log->file->last - log->file->pos != buf) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "access_log \"%V\" already defined "
+                               "with different buffer size", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        log->file->buffer = ngx_palloc(cf->pool, buf);
+        if (log->file->buffer == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        log->file->pos = log->file->buffer;
+        log->file->last = log->file->buffer + buf;
+    }
+
+    return NGX_CONF_OK;
 }
 
 
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -36,6 +36,8 @@ static ngx_http_variable_value_t *
     ngx_http_variable_request_method(ngx_http_request_t *r, uintptr_t data);
 static ngx_http_variable_value_t *
     ngx_http_variable_remote_user(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
+    ngx_http_variable_sent(ngx_http_request_t *r, uintptr_t data);
 
 
 /*
@@ -44,8 +46,7 @@ static ngx_http_variable_value_t *
  *                 REMOTE_HOST (null), REMOTE_IDENT (null),
  *                 SERVER_SOFTWARE
  *
- *     Apache SSI: DATE_GMT, DOCUMENT_NAME, LAST_MODIFIED,
- *                 USER_NAME (file owner)
+ *     Apache SSI: DOCUMENT_NAME, LAST_MODIFIED, USER_NAME (file owner)
  */
 
 static ngx_http_variable_t  ngx_http_core_variables[] = {
@@ -116,6 +117,10 @@ static ngx_http_variable_t  ngx_http_cor
 
     { ngx_string("remote_user"), ngx_http_variable_remote_user, 0, 0, 0 },
 
+    { ngx_string("sent"), ngx_http_variable_sent, 0, 0, 0 },
+
+    { ngx_string("apache_sent"), ngx_http_variable_sent, 1, 0, 0 },
+
     { ngx_null_string, NULL, 0, 0, 0 }
 };
 
@@ -699,6 +704,41 @@ ngx_http_variable_remote_user(ngx_http_r
 }
 
 
+static ngx_http_variable_value_t *
+ngx_http_variable_sent(ngx_http_request_t *r, uintptr_t data)
+{
+    off_t                       sent;
+    u_char                     *p;
+    ngx_http_variable_value_t  *vv;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    sent = r->connection->sent;
+
+    if (data) {
+        sent -= r->header_size;
+
+        if (sent < 0) {
+            sent = 0;
+        }
+    }
+
+    p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
+    if (p == NULL) {
+        return NULL;
+    }
+
+    vv->value = 0;
+    vv->text.len = ngx_sprintf(p, "%O", sent) - p;
+    vv->text.data = p;
+
+    return vv;
+}
+
+
 ngx_int_t
 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
 {
--- a/src/imap/ngx_imap.h
+++ b/src/imap/ngx_imap.h
@@ -157,10 +157,6 @@ typedef struct {
 #define NGX_IMAP_PARSE_INVALID_COMMAND  20
 
 
-#define NGX_IMAP_PROXY_INVALID  10
-#define NGX_IMAP_PROXY_ERROR    11
-
-
 #define NGX_IMAP_MODULE      0x50414D49     /* "IMAP" */
 
 #define NGX_IMAP_MAIN_CONF   0x02000000
--- a/src/imap/ngx_imap_proxy_module.c
+++ b/src/imap/ngx_imap_proxy_module.c
@@ -32,8 +32,8 @@ static char *ngx_imap_proxy_merge_conf(n
     void *child);
 
 
-#define NGX_IMAP_WAIT_OK    0
-#define NGX_IMAP_WAIT_NEXT  1
+#define NGX_IMAP_WAIT_OK      0
+#define NGX_IMAP_WAIT_NEXT    1
 
 
 static ngx_command_t  ngx_imap_proxy_commands[] = {
@@ -156,7 +156,6 @@ ngx_imap_proxy_block_read(ngx_event_t *r
 static void
 ngx_imap_proxy_imap_handler(ngx_event_t *rev)
 {
-    char                   *action;
     u_char                 *p;
     ngx_int_t               rc;
     ngx_str_t               line;
@@ -194,21 +193,11 @@ ngx_imap_proxy_imap_handler(ngx_event_t 
         return;
     }
 
-    if (rc == NGX_ERROR || rc == NGX_IMAP_PROXY_INVALID) {
+    if (rc == NGX_ERROR) {
         ngx_imap_proxy_internal_server_error(s);
         return;
     }
 
-    if (rc == NGX_IMAP_PROXY_ERROR) {
-        s->connection->read->handler = ngx_imap_proxy_handler;
-        s->connection->write->handler = ngx_imap_proxy_handler;
-        rev->handler = ngx_imap_proxy_handler;
-        c->write->handler = ngx_imap_proxy_handler;
-
-        ngx_imap_proxy_handler(c->read);
-        return;
-    }
-
     switch (s->imap_state) {
 
     case ngx_imap_start:
@@ -294,10 +283,8 @@ ngx_imap_proxy_imap_handler(ngx_event_t 
         ngx_add_timer(s->connection->read, pcf->timeout);
         ngx_del_timer(c->read);
 
-        action = c->log->action;
         c->log->action = NULL;
         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
-        c->log->action = action;
 
         c->log->action = "proxying";
     }
@@ -307,7 +294,6 @@ ngx_imap_proxy_imap_handler(ngx_event_t 
 static void
 ngx_imap_proxy_pop3_handler(ngx_event_t *rev)
 {
-    char                   *action;
     u_char                 *p;
     ngx_int_t               rc;
     ngx_str_t               line;
@@ -344,21 +330,11 @@ ngx_imap_proxy_pop3_handler(ngx_event_t 
         return;
     }
 
-    if (rc == NGX_ERROR || rc == NGX_IMAP_PROXY_INVALID) {
+    if (rc == NGX_ERROR) {
         ngx_imap_proxy_internal_server_error(s);
         return;
     }
 
-    if (rc == NGX_IMAP_PROXY_ERROR) {
-        s->connection->read->handler = ngx_imap_proxy_handler;
-        s->connection->write->handler = ngx_imap_proxy_handler;
-        rev->handler = ngx_imap_proxy_handler;
-        c->write->handler = ngx_imap_proxy_handler;
-
-        ngx_imap_proxy_handler(c->read);
-        return;
-    }
-
     switch (s->imap_state) {
 
     case ngx_pop3_start:
@@ -425,10 +401,8 @@ ngx_imap_proxy_pop3_handler(ngx_event_t 
         ngx_add_timer(s->connection->read, pcf->timeout);
         ngx_del_timer(c->read);
 
-        action = c->log->action;
         c->log->action = NULL;
         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
-        c->log->action = action;
 
         c->log->action = "proxying";
     }
@@ -474,7 +448,7 @@ ngx_imap_proxy_read_response(ngx_imap_se
             ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                           "upstream sent too long response line: \"%s\"",
                           b->pos);
-            return NGX_IMAP_PROXY_INVALID;
+            return NGX_ERROR;
         }
 
         return NGX_AGAIN;
@@ -487,15 +461,7 @@ ngx_imap_proxy_read_response(ngx_imap_se
             return NGX_OK;
         }
 
-        if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') {
-            return NGX_IMAP_PROXY_ERROR;
-        }
-
     } else {
-        if (p[0] == 'N' && p[1] == 'O') {
-            return NGX_IMAP_PROXY_ERROR;
-        }
-
         if (what == NGX_IMAP_WAIT_OK) {
             if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
                 return NGX_OK;
@@ -512,7 +478,7 @@ ngx_imap_proxy_read_response(ngx_imap_se
     ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                   "upstream sent invalid response: \"%s\"", p);
 
-    return NGX_IMAP_PROXY_INVALID;
+    return NGX_ERROR;
 }
 
 
--- a/src/os/unix/ngx_atomic.h
+++ b/src/os/unix/ngx_atomic.h
@@ -154,7 +154,7 @@ static ngx_inline ngx_atomic_uint_t
 ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
      ngx_atomic_uint_t set)
 {
-     if (*lock == old {
+     if (*lock == old) {
          *lock = set;
          return 1;
      }
@@ -174,9 +174,10 @@ ngx_atomic_fetch_add(ngx_atomic_t *value
      return old;
 }
 
+#define ngx_memory_barrier()
+
 #endif
 
-
 void ngx_spinlock(ngx_atomic_t *lock, ngx_uint_t spin);
 
 #define ngx_trylock(lock)  (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1))
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -44,7 +44,6 @@ ngx_fd_t ngx_open_tempfile(u_char *name,
 ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset);
 #define ngx_read_file_n          "read()"
 
-
 ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size,
     off_t offset);
 
@@ -52,6 +51,11 @@ ssize_t ngx_write_chain_to_file(ngx_file
     off_t offset, ngx_pool_t *pool);
 
 
+#define ngx_write_fd             write
+#define ngx_linefeed(p)          *p++ = LF;
+#define NGX_LINEFEED_SIZE        1
+
+
 #define ngx_rename_file          rename
 #define ngx_rename_file_n        "rename"
 
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -276,6 +276,13 @@ ngx_single_process_cycle(ngx_cycle_t *cy
         ngx_process_events_and_timers(cycle);
 
         if (ngx_terminate || ngx_quit) {
+
+            for (i = 0; ngx_modules[i]; i++) {
+                if (ngx_modules[i]->exit_process) {
+                    ngx_modules[i]->exit_process(cycle);
+                }
+            }
+
             ngx_master_exit(cycle);
         }
 
@@ -623,10 +630,18 @@ ngx_reap_childs(ngx_cycle_t *cycle)
 static void
 ngx_master_exit(ngx_cycle_t *cycle)
 {
+    ngx_uint_t  i;
+
     ngx_delete_pidfile(cycle);
 
     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit");
 
+    for (i = 0; ngx_modules[i]; i++) {
+        if (ngx_modules[i]->exit_master) {
+            ngx_modules[i]->exit_master(cycle);
+        }
+    }
+
     /*
      * we do not destroy cycle->pool here because a signal handler
      * that uses cycle->log can be called at this point
@@ -735,6 +750,12 @@ ngx_worker_process_cycle(ngx_cycle_t *cy
             ngx_wakeup_worker_threads(cycle);
 #endif
 
+            for (i = 0; ngx_modules[i]; i++) {
+                if (ngx_modules[i]->exit_process) {
+                    ngx_modules[i]->exit_process(cycle);
+                }
+            }
+
             c = cycle->connections;
             for (i = 0; i < cycle->connection_n; i++) {
                 if (c[i].fd != -1
--- a/src/os/win32/ngx_files.h
+++ b/src/os/win32/ngx_files.h
@@ -65,6 +65,11 @@ ngx_int_t ngx_file_append_mode(ngx_fd_t 
 #define ngx_close_file_n            "CloseHandle()"
 
 
+#define ngx_write_fd(fd, buf, size) WriteFile(fd, buf, size, NULL, NULL)
+#define ngx_linefeed(p)             *p++ = CR; *p++ = LF;
+#define NGX_LINEFEED_SIZE           2
+
+
 #define ngx_delete_file(name)       DeleteFile((const char *) name)
 #define ngx_delete_file_n           "DeleteFile()"