From: Greg Stein Date: Wed, 24 Jan 2001 06:17:26 +0000 (+0000) Subject: A single outermost loop is all that is needed. Simplify and add comments X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1f1392f43680400e9337714ceb6dc5a29c379fe8;p=apache A single outermost loop is all that is needed. Simplify and add comments about what is going on in there. Shift some declarations to scope their usage and (re)initialize them on each pass over the brigade. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@87811 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/http/http_core.c b/modules/http/http_core.c index 4545cb4761..5863f80dd7 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -3314,28 +3314,19 @@ static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mod typedef struct CORE_OUTPUT_FILTER_CTX { apr_bucket_brigade *b; } core_output_filter_ctx_t; + #define MAX_IOVEC_TO_WRITE 16 + static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b) { apr_status_t rv; - apr_bucket_brigade *more = NULL; - apr_size_t bytes_sent = 0, nbytes; - apr_bucket *e; conn_rec *c = f->c; core_output_filter_ctx_t *ctx = f->ctx; - apr_size_t nvec = 0; - apr_size_t nvec_trailers= 0; - struct iovec vec[MAX_IOVEC_TO_WRITE]; - struct iovec vec_trailers[MAX_IOVEC_TO_WRITE]; - - apr_file_t *fd = NULL; - apr_size_t flen = 0; - apr_off_t foffset = 0; - if (ctx == NULL) { f->ctx = ctx = apr_pcalloc(c->pool, sizeof(core_output_filter_ctx_t)); } + /* If we have a saved brigade, concatenate the new brigade to it */ if (ctx->b) { APR_BRIGADE_CONCAT(ctx->b, b); @@ -3343,152 +3334,183 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b) ctx->b = NULL; } - /* Iterate over the brigade collecting iovecs */ - do { - while (b) { - nbytes = 0; /* in case more points to another brigade */ - APR_BRIGADE_FOREACH(e, b) { - if (APR_BUCKET_IS_EOS(e) || APR_BUCKET_IS_FLUSH(e)) { + /* Perform multiple passes over the brigade, sending batches of output + to the connection. */ + while (b) { + apr_size_t nbytes = 0; + apr_bucket *e; + + /* tail of brigade if we need another pass */ + apr_bucket_brigade *more = NULL; + + /* one group of iovecs per pass over the brigade */ + apr_size_t nvec = 0; + apr_size_t nvec_trailers = 0; + struct iovec vec[MAX_IOVEC_TO_WRITE]; + struct iovec vec_trailers[MAX_IOVEC_TO_WRITE]; + + /* one file per pass over the brigade */ + apr_file_t *fd = NULL; + apr_size_t flen = 0; + apr_off_t foffset = 0; + + /* Iterate over the brigade: collect iovecs and/or a file */ + APR_BRIGADE_FOREACH(e, b) { + if (APR_BUCKET_IS_EOS(e) || APR_BUCKET_IS_FLUSH(e)) { + break; + } + /* It doesn't make any sense to use sendfile for a file bucket + * that represents 10 bytes. + */ + else if (APR_BUCKET_IS_FILE(e) + && (e->length >= AP_MIN_SENDFILE_BYTES)) { + apr_bucket_shared *s = e->data; + apr_bucket_file *a = s->data; + + /* We can't handle more than one file bucket at a time + * so we split here and send the file we have already + * found. + */ + if (fd) { + more = apr_brigade_split(b, e); break; } - /* It doesn't make any sense to use sendfile for a file bucket - * that represents 10 bytes. - */ - else if (APR_BUCKET_IS_FILE(e) && (e->length >= AP_MIN_SENDFILE_BYTES)) { - apr_bucket_shared *s = e->data; - apr_bucket_file *a = s->data; - /* We can't handle more than one file bucket at a time - * so we split here and send the file we have already found. - */ - if (fd) { - more = apr_brigade_split(b, e); - break; + fd = a->fd; + flen = e->length; + foffset = s->start; + } + else { + const char *str; + apr_size_t n; + + rv = apr_bucket_read(e, &str, &n, APR_BLOCK_READ); + if (n) { + nbytes += n; + if (!fd) { + vec[nvec].iov_base = (char*) str; + vec[nvec].iov_len = n; + nvec++; } - - fd = a->fd; - flen = e->length; - foffset = s->start; - } - else { - const char *str; - apr_size_t n; - rv = apr_bucket_read(e, &str, &n, APR_BLOCK_READ); - if (n) { - nbytes += n; - if (!fd) { - vec[nvec].iov_base = (char*) str; - vec[nvec].iov_len = n; - nvec++; - } - else { - /* The bucket is a trailer to a file bucket */ - vec_trailers[nvec_trailers].iov_base = (char*) str; - vec_trailers[nvec_trailers].iov_len = n; - nvec_trailers++; - } + else { + /* The bucket is a trailer to a file bucket */ + vec_trailers[nvec_trailers].iov_base = (char*) str; + vec_trailers[nvec_trailers].iov_len = n; + nvec_trailers++; } } + } - if ((nvec == MAX_IOVEC_TO_WRITE) || - (nvec_trailers == MAX_IOVEC_TO_WRITE)) { - /* Split the brigade and break */ - if (APR_BUCKET_NEXT(e) != APR_BRIGADE_SENTINEL(b)) { - more = apr_brigade_split(b, APR_BUCKET_NEXT(e)); - } - break; + if ((nvec == MAX_IOVEC_TO_WRITE) || + (nvec_trailers == MAX_IOVEC_TO_WRITE)) { + /* Split the brigade and break */ + if (APR_BUCKET_NEXT(e) != APR_BRIGADE_SENTINEL(b)) { + more = apr_brigade_split(b, APR_BUCKET_NEXT(e)); } + break; } + } - /* Completed iterating over the brigades, now determine if we want - * to buffer the brigade or send the brigade out on the network - */ - if ((!fd && (!more) && - (nbytes < AP_MIN_BYTES_TO_WRITE) && !APR_BUCKET_IS_FLUSH(e)) - || (APR_BUCKET_IS_EOS(e) && c->keepalive)) { + /* Completed iterating over the brigades, now determine if we want + * to buffer the brigade or send the brigade out on the network. + * + * Save if: + * + * 1) we didn't see a file, we don't have more passes over the + * brigade to perform, we haven't accumulated enough bytes to + * send, AND we didn't stop at a FLUSH bucket. + * (IOW, we will save away plain old bytes) + * or + * 2) we hit the EOS and have a keep-alive connection + * (IOW, this response is a bit more complex, but we save it + * with the hope of concatenating with another response) + */ + if ((!fd && !more && + (nbytes < AP_MIN_BYTES_TO_WRITE) && !APR_BUCKET_IS_FLUSH(e)) + || (APR_BUCKET_IS_EOS(e) && c->keepalive)) { - /* NEVER save an EOS in here. If we are saving a brigade with - * an EOS bucket, then we are doing keepalive connections, and - * we want to process to second request fully. - */ - if (APR_BUCKET_IS_EOS(e)) { - APR_BUCKET_REMOVE(e); - apr_bucket_destroy(e); - } - ap_save_brigade(f, &ctx->b, &b); - return APR_SUCCESS; + /* NEVER save an EOS in here. If we are saving a brigade with + * an EOS bucket, then we are doing keepalive connections, and + * we want to process to second request fully. + */ + if (APR_BUCKET_IS_EOS(e)) { + APR_BUCKET_REMOVE(e); + apr_bucket_destroy(e); } - if (fd) { - apr_hdtr_t hdtr; + ap_save_brigade(f, &ctx->b, &b); + return APR_SUCCESS; + } + + if (fd) { + apr_hdtr_t hdtr; #if APR_HAS_SENDFILE - apr_int32_t flags = 0; + apr_int32_t flags = 0; #endif - memset(&hdtr, '\0', sizeof(hdtr)); - if (nvec) { - hdtr.numheaders = nvec; - hdtr.headers = vec; - } - if (nvec_trailers) { - hdtr.numtrailers = nvec_trailers; - hdtr.trailers = vec_trailers; - } + memset(&hdtr, '\0', sizeof(hdtr)); + if (nvec) { + hdtr.numheaders = nvec; + hdtr.headers = vec; + } + if (nvec_trailers) { + hdtr.numtrailers = nvec_trailers; + hdtr.trailers = vec_trailers; + } #if APR_HAS_SENDFILE - if (!c->keepalive) { - /* Prepare the socket to be reused */ - flags |= APR_SENDFILE_DISCONNECT_SOCKET; - } - rv = sendfile_it_all(c, /* the connection */ - fd, /* the file to send */ - &hdtr, /* header and trailer iovecs */ - foffset, /* offset in the file to begin - sending from */ - flen, /* length of file */ - nbytes + flen, /* total length including - headers */ - flags); /* apr_sendfile flags */ + if (!c->keepalive) { + /* Prepare the socket to be reused */ + flags |= APR_SENDFILE_DISCONNECT_SOCKET; + } + rv = sendfile_it_all(c, /* the connection */ + fd, /* the file to send */ + &hdtr, /* header and trailer iovecs */ + foffset, /* offset in the file to begin + sending from */ + flen, /* length of file */ + nbytes + flen, /* total length including + headers */ + flags); /* apr_sendfile flags */ - /* If apr_sendfile() returns APR_ENOTIMPL, call send_the_file() - * to loop on apr_read/apr_send to send the file. Our Windows - * binary distributions (which work on Windows 9x/NT) are - * compiled on Windows NT. TransmitFile is not available on - * Windows 95/98 and we discover this at runtime when - * apr_sendfile() returns APR_ENOTIMPL. Having apr_sendfile() - * return APR_ENOTIMPL seems the cleanest way to handle this - * case. - */ - if (rv == APR_ENOTIMPL) { + /* If apr_sendfile() returns APR_ENOTIMPL, call send_the_file() + * to loop on apr_read/apr_send to send the file. Our Windows + * binary distributions (which work on Windows 9x/NT) are + * compiled on Windows NT. TransmitFile is not available on + * Windows 95/98 and we discover this at runtime when + * apr_sendfile() returns APR_ENOTIMPL. Having apr_sendfile() + * return APR_ENOTIMPL seems the cleanest way to handle this + * case. + */ + if (rv == APR_ENOTIMPL) { #endif - - rv = send_the_file(c, fd, &hdtr, foffset, flen, &bytes_sent); + apr_size_t unused_bytes_sent; + + rv = send_the_file(c, fd, &hdtr, foffset, flen, + &unused_bytes_sent); #if APR_HAS_SENDFILE - } -#endif - fd = NULL; - } - else { - rv = writev_it_all(c->client_socket, - vec, nvec, - nbytes, &bytes_sent); } - - apr_brigade_destroy(b); - if (rv != APR_SUCCESS) { - /* XXX: log the error */ - if (more) - apr_brigade_destroy(more); - return rv; - } - nvec = 0; - nvec_trailers = 0; - - b = more; - more = NULL; - } /* end while () */ +#endif + fd = NULL; + } + else { + apr_size_t unused_bytes_sent; + + rv = writev_it_all(c->client_socket, + vec, nvec, + nbytes, &unused_bytes_sent); + } + apr_brigade_destroy(b); + if (rv != APR_SUCCESS) { + /* XXX: log the error */ + if (more) + apr_brigade_destroy(more); + return rv; + } + b = more; - } while (more); + more = NULL; + } /* end while () */ return APR_SUCCESS; }