# HG changeset patch # User Igor Sysoev # Date 1087761255 0 # Node ID 446782c909b3bbe3d70e0f0bc1085f3590662206 # Parent 239e37d44a341dbac2adf3ef6dbc0916c7ade3bb nginx-0.0.7-2004-06-20-23:54:15 import diff --git a/auto/types/maxvalue b/auto/types/maxvalue 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 diff --git a/auto/unix b/auto/unix --- 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 diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- 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; } diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c --- 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) { diff --git a/src/event/ngx_event_timer.h b/src/event/ngx_event_timer.h --- 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); diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- 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); } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- 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; diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c --- 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; } diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -35,6 +35,22 @@ #include #include /* TCP_NOPUSH */ + +#if __FreeBSD_version < 400017 + +#include /* 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 diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- 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; diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- 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) { diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- 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)) {