changeset 361:446782c909b3

nginx-0.0.7-2004-06-20-23:54:15 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 20 Jun 2004 19:54:15 +0000
parents 239e37d44a34
children 7650aea1816f
files auto/types/maxvalue auto/unix src/event/ngx_event.h src/event/ngx_event_timer.c src/event/ngx_event_timer.h src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_write_filter.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd_init.c src/os/unix/ngx_freebsd_sendfile_chain.c src/os/unix/ngx_process_cycle.c
diffstat 12 files changed, 176 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/auto/types/maxvalue
@@ -0,0 +1,6 @@
+
+cat << END >> $NGX_AUTO_CONFIG_H
+
+#ifndef $ngx_type_max_value
+#define $ngx_type_max_value  $ngx_max_size
+#endif
--- a/auto/unix
+++ b/auto/unix
@@ -46,6 +46,7 @@ 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_fmt_name=TIME_T_FMT; ngx_type="time_t"; . auto/types/sizeof
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -91,8 +91,6 @@ struct ngx_event_s {
     unsigned short   timedout:1;
     unsigned short   timer_set:1;
 
-    unsigned short   delayed:1;
-
     unsigned short   read_discarded:1;
 
     unsigned short   unexpected_eof:1;
@@ -499,7 +497,7 @@ ngx_inline static int ngx_handle_read_ev
         }
     }
 
-    /* aio, iocp, epoll, rt signals */
+    /* aio, iocp, epoll, rtsig */
 
     return NGX_OK;
 }
@@ -570,7 +568,7 @@ ngx_inline static int ngx_handle_write_e
         }
     }
 
-    /* aio, iocp, epoll, rt signals */
+    /* aio, iocp, epoll, rtsig */
 
     return NGX_OK;
 }
--- a/src/event/ngx_event_timer.c
+++ b/src/event/ngx_event_timer.c
@@ -91,15 +91,7 @@ void ngx_event_expire_timers(ngx_msec_t 
 
             ngx_del_timer(ev);
 
-            if (ev->delayed) {
-                ev->delayed = 0;
-                if (ev->ready == 0) {
-                    continue;
-                }
-
-            } else {
-                ev->timedout = 1;
-            }
+            ev->timedout = 1;
 
             if (ngx_threaded) {
                 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
--- a/src/event/ngx_event_timer.h
+++ b/src/event/ngx_event_timer.h
@@ -85,7 +85,7 @@ ngx_inline static void ngx_event_add_tim
          * for the fast connections.
          */
 
-        if (key - ev->rbtree_key < 100 / NGX_TIMER_RESOLUTION) {
+        if (abs(key - ev->rbtree_key) < 100 / NGX_TIMER_RESOLUTION) {
             ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                            "event timer: %d, old: %d, new: %d",
                             ngx_event_ident(ev->data), ev->rbtree_key, key);
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1050,13 +1050,15 @@ static void ngx_http_set_write_handler(n
     wev = r->connection->write;
     wev->event_handler = ngx_http_writer;
 
-    if (wev->delayed && wev->ready) {
+    if (wev->ready && r->delayed) {
         return;
     }
 
     clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
                                         ngx_http_core_module);
-    ngx_add_timer(wev, clcf->send_timeout);
+    if (!r->delayed) {
+        ngx_add_timer(wev, clcf->send_timeout);
+    }
 
     wev->available = clcf->send_lowat;
     if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) {
@@ -1080,15 +1082,36 @@ void ngx_http_writer(ngx_event_t *wev)
     c = wev->data;
     r = c->data;
 
-#if 0 /* TODO: THINK */
-    if (wev->delayed) {
-        return;
-    }
-#endif
+    if (wev->timedout) {
+        if (!r->delayed) {
+            ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
+            return;
+        }
+
+        wev->timedout = 0;
+        r->delayed = 0;
+
+        if (!wev->ready) {
+            clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
+                                                ngx_http_core_module);
+            ngx_add_timer(wev, clcf->send_timeout);
 
-    if (wev->timedout) {
-        ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
-        return;
+            wev->available = clcf->send_lowat;
+
+            if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) {
+                ngx_http_close_request(r, 0);
+                ngx_http_close_connection(r->connection);
+            }
+
+            return;
+        }
+
+    } else {
+        if (r->delayed) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
+                           "http writer delayed");
+            return;
+        }
     }
 
     rc = ngx_http_output_filter(r, NULL);
@@ -1097,13 +1120,15 @@ void ngx_http_writer(ngx_event_t *wev)
                   "http writer output filter: %d", rc);
 
     if (rc == NGX_AGAIN) {
-        if (!wev->ready) {
-            clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
-                                                ngx_http_core_module);
+        clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
+                                            ngx_http_core_module);
+        if (!wev->ready && !r->delayed) {
             ngx_add_timer(wev, clcf->send_timeout);
         }
 
-        if (ngx_handle_level_write_event(wev) == NGX_ERROR) {
+        wev->available = clcf->send_lowat;
+
+        if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) {
             ngx_http_close_request(r, 0);
             ngx_http_close_connection(r->connection);
         }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -284,6 +284,7 @@ struct ngx_http_request_s {
     /* can we use sendfile ? */
     unsigned             sendfile:1;
 
+    unsigned             delayed:1;
     unsigned             chunked:1;
     unsigned             header_only:1;
     unsigned             keepalive:1;
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -69,7 +69,7 @@ ngx_module_t  ngx_http_write_filter_modu
 ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
     int                            last;
-    off_t                          size, flush;
+    off_t                          size, flush, sent;
     ngx_chain_t                   *cl, *ln, **ll, *chain;
     ngx_http_write_filter_ctx_t   *ctx;
     ngx_http_write_filter_conf_t  *conf;
@@ -138,7 +138,7 @@ ngx_int_t ngx_http_write_filter(ngx_http
         return NGX_OK;
     }
 
-    if (r->connection->write->delayed) {
+    if (r->delayed) {
         return NGX_AGAIN;
     }
 
@@ -150,11 +150,19 @@ ngx_int_t ngx_http_write_filter(ngx_http
         return NGX_OK;
     }
 
+    sent = r->connection->sent;
+
     chain = ngx_write_chain(r->connection, ctx->out);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http write filter %X", chain);
 
+#if 1
+    sent = r->connection->sent - sent;
+    r->delayed = 1;
+    ngx_add_timer(r->connection->write, sent * 1000 / (4 * 1024));
+#endif
+
     if (chain == NGX_CHAIN_ERROR) {
         return NGX_ERROR;
     }
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -35,6 +35,22 @@
 #include <sys/sysctl.h>
 #include <netinet/tcp.h>        /* TCP_NOPUSH */
 
+
+#if __FreeBSD_version < 400017
+
+#include <sys/param.h>          /* ALIGN() */
+
+/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */
+
+#undef  CMSG_SPACE
+#define CMSG_SPACE(l)       (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l))
+
+#undef  CMSG_DATA
+#define CMSG_DATA(cmsg)     ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr)))
+
+#endif
+
+
 #include <ngx_auto_config.h>
 
 
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -121,15 +121,18 @@ int ngx_os_init(ngx_log_t *log)
 #if (HAVE_SENDFILE)
 
     /*
-     * The determination of the sendfile() nbytes bug is complex enough.
+     * The determination of the sendfile() "nbytes bug" is complex enough.
      * There are two sendfile() syscalls: a new #393 has no bug while
      * an old #336 has the bug in some versions and has not in others.
      * Besides libc_r wrapper also emulates the bug in some versions.
      * There's no way to say exactly if a given FreeBSD version has the bug.
-     * Here is the algorithm that works at least for RELEASEs
+     * We use the algorithm that is correct at least for RELEASEs
      * and for syscalls only (not libc_r wrapper).
      *
-     * We detect the new sendfile() version available at the compile time
+     * 4.6.1-RELEASE and below have the bug
+     * 4.6.2-RELEASE and above have the new syscall
+     *
+     * We detect the new sendfile() syscall available at the compile time
      * to allow an old binary to run correctly on an updated FreeBSD system.
      */
 
@@ -142,7 +145,7 @@ int ngx_os_init(ngx_log_t *log)
 
 #else
 
-    /* an old syscall that can have the bug */
+    /* an old syscall that may have the bug */
 
     ngx_freebsd_sendfile_nbytes_bug = 1;
 
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -11,9 +11,9 @@
 
 /*
  * Although FreeBSD sendfile() allows to pass a header and a trailer
- * it never sends a header with a part of the file in one packet until
+ * it can not send a header with a part of the file in one packet until
  * FreeBSD 5.2-STABLE.  Besides over the fast ethernet connection sendfile()
- * can send the partially filled packets, i.e. the 8 file pages can be sent
+ * may send the partially filled packets, i.e. the 8 file pages may be sent
  * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet,
  * and then again the 11 full 1460-bytes packets.
  *
@@ -22,7 +22,7 @@
  * of the file in one packet but also sends file pages in the full packets.
  *
  * But until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending
- * data that less than MSS so that data can be sent with 5 second delay.
+ * data that less than MSS so that data may be sent with 5 second delay.
  * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used
  * for non-keepalive HTTP connections.
  */
@@ -32,10 +32,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 {
     int              rc;
     u_char          *prev;
-    off_t            sent, fprev;
+    off_t            sent, fprev, send, limit;
     size_t           hsize, fsize;
     ssize_t          size;
-    ngx_int_t        eintr, eagain;
+    ngx_uint_t       eintr, eagain, ready;
     struct iovec    *iov;
     struct sf_hdtr   hdtr;
     ngx_err_t        err;
@@ -62,12 +62,20 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 
 #endif
 
+#if 1
+    limit = 4096;
+#else
+    limit = OFF_T_MAX_VALUE;
+#endif
+
     do {
         file = NULL;
         fsize = 0;
         hsize = 0;
+        send = 0;
         eintr = 0;
         eagain = 0;
+        ready = 0;
 
         ngx_init_array(header, c->pool, 10, sizeof(struct iovec),
                        NGX_CHAIN_ERROR);
@@ -88,40 +96,50 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                 break;
             }
 
+            size = cl->buf->last - cl->buf->pos;
+
+            if (send + size > limit) {
+                size = limit - send;
+            }
+
             if (prev == cl->buf->pos) {
-                iov->iov_len += cl->buf->last - cl->buf->pos;
+                iov->iov_len += size;
 
             } else {
                 ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR);
                 iov->iov_base = (void *) cl->buf->pos;
-                iov->iov_len = cl->buf->last - cl->buf->pos;
+                iov->iov_len = size;
             }
 
-            prev = cl->buf->last;
-            hsize += cl->buf->last - cl->buf->pos;
+            prev = cl->buf->pos + size;
+            hsize += size;
+            send += size;
         }
 
         /* get the file buf */
 
         if (cl && cl->buf->in_file) {
             file = cl->buf;
-            fsize = (size_t) (file->file_last - file->file_pos);
-            fprev = file->file_last;
-            cl = cl->next;
+            fsize = 0;
 
             /* coalesce the neighbouring file bufs */
 
-            while (cl && cl->buf->in_file) {
-                if (file->file->fd != cl->buf->file->fd
-                    || fprev != cl->buf->file_pos)
-                {
-                    break;
+            do {
+                size = (size_t) (cl->buf->file_last - cl->buf->file_pos);
+
+                if (send + size > limit) {
+                    size = limit - send;
                 }
 
-                fsize += (size_t) (cl->buf->file_last - cl->buf->file_pos);
-                fprev = cl->buf->file_last;
+                fsize += size;
+                send += size;
+                fprev = cl->buf->file_pos + size;
                 cl = cl->next;
-            }
+
+            } while (cl
+                     && cl->buf->in_file
+                     && file->file->fd == cl->buf->file->fd
+                     && fprev == cl->buf->file_pos);
         }
 
         if (file) {
@@ -139,17 +157,24 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                     break;
                 }
 
+                size = cl->buf->last - cl->buf->pos;
+
+                if (send + size > limit) {
+                    size = limit - send;
+                }
+
                 if (prev == cl->buf->pos) {
-                    iov->iov_len += cl->buf->last - cl->buf->pos;
+                    iov->iov_len += size;
 
                 } else {
                     ngx_test_null(iov, ngx_push_array(&trailer),
                                   NGX_CHAIN_ERROR);
                     iov->iov_base = (void *) cl->buf->pos;
-                    iov->iov_len = cl->buf->last - cl->buf->pos;
+                    iov->iov_len = size;
                 }
 
-                prev = cl->buf->last;
+                prev = cl->buf->pos + size;
+                send += size;
             }
         }
 
@@ -261,6 +286,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             sent = rc > 0 ? rc : 0;
         }
 
+        if (send == sent) {
+            ready = 1;
+        }
+
         c->sent += sent;
 
         for (cl = in; cl; cl = cl->next) {
@@ -300,6 +329,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             break;
         }
 
+        if (ready) {
+            return cl;
+        }
+
         in = cl;
 
         if (eagain) {
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -763,26 +763,30 @@ int ngx_worker_thread_cycle(void *data)
 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;
+    ssize_t             n;
+    ngx_err_t           err;
+    struct iovec        iov[1];
+    struct msghdr       msg;
 
 #if (HAVE_MSGHDR_MSG_CONTROL)
 
+    union {
+        struct cmsghdr  cm;
+        char            space[CMSG_SPACE(sizeof(int))];
+    } cmsg;
+
     if (ch->fd == -1) {
         msg.msg_control = NULL;
         msg.msg_controllen = 0;
 
     } else {
-        msg.msg_control = (caddr_t) &cm;
-        msg.msg_controllen = sizeof(struct cmsghdr) +  sizeof(int);
+        msg.msg_control = (caddr_t) &cmsg;
+        msg.msg_controllen = sizeof(cmsg);
 
-        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;
+        cmsg.cm.cmsg_len = sizeof(cmsg);
+        cmsg.cm.cmsg_level = SOL_SOCKET; 
+        cmsg.cm.cmsg_type = SCM_RIGHTS;
+        *(int *) CMSG_DATA(&cmsg) = ch->fd;
     }
 
 #else
@@ -825,12 +829,19 @@ ngx_int_t ngx_write_channel(ngx_socket_t
 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;
+    ssize_t             n;
+    ngx_err_t           err;
+    struct iovec        iov[1];
+    struct msghdr       msg;
+
+#if (HAVE_MSGHDR_MSG_CONTROL)
+    union {
+        struct cmsghdr  cm;
+        char            space[CMSG_SPACE(sizeof(int))];
+    } cmsg;
+#else
+    int                 fd;
+#endif
 
     iov[0].iov_base = (char *) ch;
     iov[0].iov_len = size;
@@ -841,8 +852,8 @@ ngx_int_t ngx_read_channel(ngx_socket_t 
     msg.msg_iovlen = 1;
 
 #if (HAVE_MSGHDR_MSG_CONTROL)
-    msg.msg_control = (caddr_t) &cm;
-    msg.msg_controllen = sizeof(struct cmsghdr) +  sizeof(int);
+    msg.msg_control = (caddr_t) &cmsg;
+    msg.msg_controllen = sizeof(cmsg);
 #else
     msg.msg_accrights = (caddr_t) &fd;
     msg.msg_accrightslen = sizeof(int);
@@ -870,20 +881,22 @@ ngx_int_t ngx_read_channel(ngx_socket_t 
 
     if (ch->command == NGX_CMD_OPEN_CHANNEL) {
 
-        if (cm.cmsg_len < sizeof(struct cmsghdr) + sizeof(int)) {
+        if (cmsg.cm.cmsg_len < sizeof(cmsg)) {
             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) {
+        if (cmsg.cm.cmsg_level != SOL_SOCKET || cmsg.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);
+                          "level %d or type %d",
+                          cmsg.cm.cmsg_level, cmsg.cm.cmsg_type);
             return NGX_ERROR;
         }
 
-        ch->fd = *((int *) ((char *) &cm + sizeof(struct cmsghdr)));
+        ch->fd = *(int *) CMSG_DATA(&cmsg);
     }
 
     if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {