diff --git a/auto/fmt/fmt b/auto/fmt/fmt index 3e19c318f..ebfbd53a9 100644 --- a/auto/fmt/fmt +++ b/auto/fmt/fmt @@ -15,7 +15,7 @@ do echo "printf(\"${FMT}\", ($NGX_TYPE) $NGX_MAX_SIZE);" >> autotest.c echo "return 0; }" >> autotest.c - eval "$CC_WARN $CC_TEST_FLAGS -o autotest autotest.c > /dev/null 2>&1" + eval "$CC_WARN $CC_TEST_FLAGS -o autotest autotest.c > $NGX_ERR 2>&1" MAX_SIZE=`echo $NGX_MAX_SIZE | sed -e "s/L*\$//"` diff --git a/auto/func b/auto/func index 553333dc0..5cde42826 100644 --- a/auto/func +++ b/auto/func @@ -1,13 +1,15 @@ echo "checking for $NGX_FUNC" +NGX_FOUND=NO + func=`echo $NGX_FUNC | sed -e 's/()$//' | tr '[a-z]' '[A-Z]'` echo "$NGX_UNISTD_H" > autotest.c echo "$NGX_FUNC_INC" >> autotest.c echo "int main() { $NGX_FUNC_TEST; return 0; }" >> autotest.c -eval "$CC $CC_TEST_FLAGS -o autotest autotest.c > /dev/null 2>&1" +eval "$CC $CC_TEST_FLAGS -o autotest autotest.c > $NGX_ERR 2>&1" if [ -x autotest ]; then echo " + $NGX_FUNC found" @@ -16,6 +18,9 @@ if [ -x autotest ]; then echo "#define HAVE_$func 1" >> $NGX_AUTO_CONFIG_H echo "#endif" >> $NGX_AUTO_CONFIG_H echo >> $NGX_AUTO_CONFIG_H + + NGX_FOUND=YES + else echo " + $NGX_FUNC not found" fi diff --git a/auto/inc b/auto/inc index 1db95f5b1..1c84eae5a 100644 --- a/auto/inc +++ b/auto/inc @@ -1,7 +1,9 @@ echo "checking for $NGX_INC" -inc=`echo $NGX_INC | sed -e 's/\./_/' | tr '[a-z]' '[A-Z]'` +NGX_FOUND=NO + +inc=`echo $NGX_INC | sed -e 's/\./_/' | sed -e 's/\//_/' | tr '[a-z]' '[A-Z]'` echo "#include <$NGX_INC>" > autotest.c echo "int main() { return 0; }" >> autotest.c @@ -17,6 +19,7 @@ if [ -x autotest ]; then echo >> $NGX_AUTO_CONFIG_H eval "NGX_$inc='#include <$NGX_INC>'" + NGX_FOUND=YES else echo " + $NGX_INC not found" diff --git a/auto/os/solaris b/auto/os/solaris index 2fe630953..008eda655 100644 --- a/auto/os/solaris +++ b/auto/os/solaris @@ -11,8 +11,24 @@ CC_TEST_FLAGS="-D_FILE_OFFSET_BITS=64" CORE_LIBS="$CORE_LIBS -lsocket -lnsl" -# STUB -CFLAGS="$CFLAGS -D HAVE_DEVPOLL=1" -EVENT_MODULES="$EVENT_MODULES $DEVPOLL_MODULE" -CORE_SRCS="$CORE_SRCS $DEVPOLL_SRCS" -#CORE_SRCS="$CORE_SRCS $LINUX_SENDFILE_SRCS" + +NGX_INC="sys/devpoll.h"; . auto/inc + +if [ $NGX_FOUND=YES ]; then + CFLAGS="$CFLAGS -D HAVE_DEVPOLL=1" + EVENT_MODULES="$EVENT_MODULES $DEVPOLL_MODULE" + CORE_SRCS="$CORE_SRCS $DEVPOLL_SRCS" +fi + + +NGX_FUNC_INC="#include " +NGX_FUNC_TEST="int fd = 1; sendfilevec_t vec[1]; + size_t sent = 1; ssize_t n; + n = sendfilev(fd, vec, 1, &sent)" +NGX_FUNC="sendfilev()"; . auto/func + +if [ $NGX_FOUND=YES ]; then + CFLAGS="$CFLAGS -D HAVE_SENDFILE=1" + CORE_SRCS="$CORE_SRCS $SOLARIS_SENDFILEV_SRCS" + CORE_LIBS="$CORE_LIBS -lsendfile" +fi diff --git a/auto/sources b/auto/sources index 2f47d15f4..f26b9404e 100644 --- a/auto/sources +++ b/auto/sources @@ -107,7 +107,7 @@ LINUX_SENDFILE_SRCS=src/os/unix/ngx_linux_sendfile_chain.c SOLARIS_DEPS=src/os/unix/ngx_solaris_config.h SOLARIS_SRCS=src/os/unix/ngx_solaris_init.c -SOLARIS_SENDFILE_SRCS=src/os/unix/ngx_solaris_sendfilev_chain.c +SOLARIS_SENDFILEV_SRCS=src/os/unix/ngx_solaris_sendfilev_chain.c WIN32_INCS="$CORE_INCS $EVENT_INCS -I src/os/win32" diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c index 80af26672..42dd14a21 100644 --- a/src/http/modules/ngx_http_static_handler.c +++ b/src/http/modules/ngx_http_static_handler.c @@ -39,12 +39,13 @@ ngx_module_t ngx_http_static_module = { }; -int ngx_http_static_translate_handler(ngx_http_request_t *r) +ngx_int_t ngx_http_static_translate_handler(ngx_http_request_t *r) { - int rc, level; + ngx_int_t rc, level; + uint32_t crc; char *location, *last; ngx_err_t err; - ngx_http_cache_ctx_t ctx; + ngx_http_cache_t *cache; ngx_http_cache_conf_t *ccf; ngx_http_core_loc_conf_t *clcf; @@ -87,23 +88,16 @@ int ngx_http_static_translate_handler(ngx_http_request_t *r) ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->file.name.data); - - /* STUB */ - ccf = NULL; - ctx.key.len = 0; - -#if 0 ccf = ngx_http_get_module_loc_conf(r, ngx_http_cache_module); if (ccf->open_files) { - ctx->hash = ccf->open_files; - ctx->key = r->file.name; + cache = ngx_http_cache_get(ccf->open_files, &r->file.name, &crc); - cache = ngx_http_cache_get_data(r, ctx); +ngx_log_debug(r->connection->log, "cache get: %x" _ cache); if (cache && ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) - || ccf->hash->life_time >= ngx_time() - cache->updated)) + || ccf->open_files->check_time >= ngx_time() - cache->updated)) { cache->refs++; r->file.fd = cache->fd; @@ -117,8 +111,6 @@ ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->file.name.data); cache = NULL; } -#endif - #if (WIN9X) if (ngx_win32_version < NGX_WIN_NT) { @@ -215,6 +207,23 @@ ngx_log_debug(r->connection->log, "FILE: %d" _ r->file.fd); r->file.info_valid = 1; } + if (ccf->open_files) { + if (cache == NULL) { + cache = ngx_http_cache_alloc(ccf->open_files, &r->file.name, crc, + r->connection->log); + } + +ngx_log_debug(r->connection->log, "cache alloc: %x" _ cache); + + if (cache) { + cache->fd = r->file.fd; + cache->data.size = ngx_file_size(&r->file.info); + cache->accessed = ngx_time(); + cache->last_modified = ngx_file_mtime(&r->file.info); + cache->updated = ngx_time(); + } + } + if (ngx_is_dir(&r->file.info)) { ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data); diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 4271da3e7..4fa657293 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -6,9 +6,11 @@ #include #include +typedef struct ngx_http_request_s ngx_http_request_t; + +#include #include #include -#include #include #include #include diff --git a/src/http/ngx_http_cache.c b/src/http/ngx_http_cache.c index 7b9cd0489..b1cd52c54 100644 --- a/src/http/ngx_http_cache.c +++ b/src/http/ngx_http_cache.c @@ -80,81 +80,87 @@ ngx_log_debug(r->connection->log, "FILE: %s" _ ctx->file.name.data); } -int ngx_http_cache_get_data(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx) +ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache, + ngx_str_t *key, uint32_t *crc) { - ngx_uint_t n, i; + ngx_uint_t i; + ngx_http_cache_t *c; - ctx->crc = ngx_crc(ctx->key.data, ctx->key.len); + *crc = ngx_crc(key->data, key->len); - n = ctx->crc % ctx->hash->hash; - for (i = 0; i < ctx->hash->nelts; i++) { - if (ctx->hash->cache[n][i].crc == ctx->crc - && ctx->hash->cache[n][i].key.len == ctx->key.len - && ngx_rstrncmp(ctx->hash->cache[n][i].key.data, ctx->key.data, - ctx->key.len) == 0) + c = cache->elts + + *crc % cache->hash * cache->nelts * sizeof(ngx_http_cache_t); + + for (i = 0; i < cache->nelts; i++) { + if (c[i].crc == *crc + && c[i].key.len == key->len + && ngx_rstrncmp(c[i].key.data, key->data, key->len) == 0) { - ctx->cache = ctx->hash->cache[n][i].data; - ctx->hash->cache[n][i].refs++; - return NGX_OK; + c[i].refs++; + return &c[i]; } } - return NGX_DECLINED; + return NULL; } -ngx_http_cache_entry_t *ngx_http_cache_get_entry(ngx_http_request_t *r, - ngx_http_cache_ctx_t *ctx) +ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *cache, + ngx_str_t *key, uint32_t crc, + ngx_log_t *log) { - time_t old; - ngx_uint_t n, i; - ngx_http_cache_entry_t *ce; + time_t old; + ngx_uint_t i; + ngx_http_cache_t *c, *found; old = ngx_time() + 1; - ce = NULL; + found = NULL; - n = ctx->crc % ctx->hash->hash; - for (i = 0; i < ctx->hash->nelts; i++) { - if (ctx->hash->cache[n][i].key.data == NULL) { + c = cache->elts + + crc % cache->hash * cache->nelts * sizeof(ngx_http_cache_t); + + for (i = 0; i < cache->nelts; i++) { + if (c[i].key.data == NULL) { /* a free entry is found */ - ce = &ctx->hash->cache[n][i]; + found = &c[i]; break; } - if (ctx->hash->cache[n][i].refs == 0 - && old > ctx->hash->cache[n][i].accessed) - { - /* looking for the oldest cache entry that is not used right now */ + /* looking for the oldest cache entry that is not been using */ - old = ctx->hash->cache[n][i].accessed; - ce = &ctx->hash->cache[n][i]; + if (c[i].refs == 0 && old > c[i].accessed) { + + old = c[i].accessed; + found = &c[i]; } } - if (ce) { - if (ce->key.data) { - if (ctx->key.len > ce->key.len) { - ngx_free(ce->key.data); - ce->key.data = NULL; + if (found) { + if (found->key.data) { + if (key->len > found->key.len) { + ngx_free(found->key.data); + found->key.data = NULL; } } - if (ce->key.data) { - ce->key.data = ngx_alloc(ctx->key.len, r->connection->log); - if (ce->key.data == NULL) { + if (found->key.data == NULL) { + found->key.data = ngx_alloc(key->len, log); + if (found->key.data == NULL) { return NULL; } } - ngx_memcpy(ce->key.data, ctx->key.data, ctx->key.len); + ngx_memcpy(found->key.data, key->data, key->len); - ce->key.len = ctx->key.len; - ce->crc = ctx->crc; + found->crc = crc; + found->key.len = key->len; + found->refs = 1; + found->deleted = 0; } - return ce; + return found; } @@ -373,24 +379,25 @@ static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf, ngx_http_cache_conf_t *prev = parent; ngx_http_cache_conf_t *conf = child; - if (conf->hash == NULL) { - if (prev->hash) { - conf->hash = prev->hash; + if (conf->open_files == NULL) { + if (prev->open_files) { + conf->open_files = prev->open_files; } else { - conf->hash = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_hash_t)); - if (conf->hash == NULL) { + conf->open_files = ngx_pcalloc(cf->pool, + sizeof(ngx_http_cache_hash_t)); + if (conf->open_files == NULL) { return NGX_CONF_ERROR; } - conf->hash->hash = NGX_HTTP_CACHE_HASH; - conf->hash->nelts = NGX_HTTP_CACHE_NELTS; + conf->open_files->hash = NGX_HTTP_CACHE_HASH; + conf->open_files->nelts = NGX_HTTP_CACHE_NELTS; - conf->hash->cache = ngx_pcalloc(cf->pool, - NGX_HTTP_CACHE_HASH - * NGX_HTTP_CACHE_NELTS - * sizeof(ngx_http_cache_entry_t)); - if (conf->hash->cache == NULL) { + conf->open_files->elts = ngx_pcalloc(cf->pool, + NGX_HTTP_CACHE_HASH + * NGX_HTTP_CACHE_NELTS + * sizeof(ngx_http_cache_t)); + if (conf->open_files->elts == NULL) { return NGX_CONF_ERROR; } } @@ -398,103 +405,3 @@ static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf, return NGX_CONF_OK; } - - -#if 0 - -/* - * small file in malloc()ed memory, mmap()ed file, file descriptor only, - * file access time only (to estimate could pages still be in memory), - * translated URI (ngx_http_index_hanlder), - * compiled script (ngx_http_ssi_filter). - */ - - -#define NGX_HTTP_CACHE_ENTRY_DELETED 0x00000001 -#define NGX_HTTP_CACHE_ENTRY_MMAPED 0x00000002 - -/* "/" -> "/index.html" in ngx_http_index_handler */ -#define NGX_HTTP_CACHE_ENTRY_URI 0x00000004 - -/* 301 location "/dir" -> "dir/" in ngx_http_core_handler */ - -/* compiled script in ngx_http_ssi_filter */ -#define NGX_HTTP_CACHE_ENTRY_SCRIPT 0x00000008 - -#define NGX_HTTP_CACHE_FILTER_FLAGS 0xFFFF0000 - - -typedef struct { - ngx_fd_t fd; - off_t size; - void *data; - time_t accessed; - time_t last_modified; - time_t updated; /* no needed with kqueue */ - int refs; - int flags; -} ngx_http_cache_entry_t; - - -typedef struct { - uint32_t crc; - ngx_str_t uri; - ngx_http_cache_t *cache; -} ngx_http_cache_hash_entry_t; - - -typedef struct { - ngx_http_cache_t *cache; - uint32_t crc; - int n; -} ngx_http_cache_handle_t; - - -int ngx_http_cache_get(ngx_http_cache_hash_t *cache_hash, - ngx_str_t *uri, ngx_http_cache_handle_t *h) -{ - int hi; - ngx_http_cache_hash_entry_t *entry; - - h->crc = ngx_crc(uri->data, uri->len); - - hi = h->crc % cache_hash->size; - entry = cache_hash[hi].elts; - - for (i = 0; i < cache_hash[hi].nelts; i++) { - if (entry[i].crc == crc - && entry[i].uri.len == uri->len - && ngx_strncmp(entry[i].uri.data, uri->data, uri->len) == 0 - { - h->cache = entry[i].cache; - h->cache->refs++; - h->n = hi; - return NGX_OK; - } - } - - return NGX_ERROR; -} - - -/* 32-bit crc16 */ - -int ngx_crc(char *data, size_t len) -{ - uint32_t sum; - - for (sum = 0; len; len--) { - /* - * gcc 2.95.2 x86 and icc 7.1.006 compile that operator - * into the single rol opcode. - * msvc 6.0sp2 compiles it into four opcodes. - */ - sum = sum >> 1 | sum << 31; - - sum += *data++; - } - - return sum; -} - -#endif diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h index 6e8042df4..768ab0f56 100644 --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -7,6 +7,26 @@ #include +typedef struct { + uint32_t crc; + ngx_str_t key; + time_t accessed; + + unsigned refs:20; /* 1048576 references */ + unsigned count:2; /* lazy allocation: the 4 uses */ + unsigned deleted:1; + + ngx_fd_t fd; + time_t last_modified; + time_t updated; + + union { + off_t size; + ngx_str_t value; + } data; +} ngx_http_cache_t; + + typedef struct { time_t expires; time_t last_modified; @@ -17,24 +37,11 @@ typedef struct { } ngx_http_cache_header_t; -typedef struct { - uint32_t crc; - ngx_str_t key; - ngx_fd_t fd; - off_t size; - void *data; /* mmap, memory */ - time_t accessed; - time_t last_modified; - time_t updated; /* no needed with kqueue */ - int refs; - int flags; -} ngx_http_cache_entry_t; - -#define NGX_HTTP_CACHE_HASH 1021 +#define NGX_HTTP_CACHE_HASH 7 #define NGX_HTTP_CACHE_NELTS 4 typedef struct { - ngx_http_cache_entry_t **cache; + ngx_http_cache_t *elts; size_t hash; size_t nelts; time_t life_time; @@ -45,12 +52,7 @@ typedef struct { typedef struct { ngx_http_cache_hash_t *hash; -} ngx_http_cache_conf_t; - - -typedef struct { - ngx_http_cache_hash_t *hash; - ngx_http_cache_entry_t *cache; + ngx_http_cache_t *cache; ngx_file_t file; ngx_str_t key; uint32_t crc; @@ -67,6 +69,11 @@ typedef struct { } ngx_http_cache_ctx_t; +typedef struct { + ngx_http_cache_hash_t *open_files; +} ngx_http_cache_conf_t; + + #define NGX_HTTP_CACHE_STALE 1 #define NGX_HTTP_CACHE_AGED 2 #define NGX_HTTP_CACHE_THE_SAME 3 @@ -74,11 +81,20 @@ typedef struct { int ngx_http_cache_get_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx); int ngx_http_cache_open_file(ngx_http_cache_ctx_t *ctx, ngx_file_uniq_t uniq); -int ngx_garbage_collector_http_cache_handler(ngx_gc_t *gc, ngx_str_t *name, - ngx_dir_t *dir); int ngx_http_cache_update_file(ngx_http_request_t *r,ngx_http_cache_ctx_t *ctx, ngx_str_t *temp_file); +ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache, + ngx_str_t *key, uint32_t *crc); +ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *cache, + ngx_str_t *key, uint32_t crc, + ngx_log_t *log); + +int ngx_garbage_collector_http_cache_handler(ngx_gc_t *gc, ngx_str_t *name, + ngx_dir_t *dir); + +extern ngx_module_t ngx_http_cache_module; + #endif /* _NGX_HTTP_CACHE_H_INCLUDED_ */ diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 2a28a67b0..3b62d58e7 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -144,8 +144,6 @@ typedef struct { } ngx_http_headers_out_t; -typedef struct ngx_http_request_s ngx_http_request_t; - typedef int (*ngx_http_handler_pt)(ngx_http_request_t *r); struct ngx_http_request_s { @@ -156,6 +154,8 @@ struct ngx_http_request_s { void **srv_conf; void **loc_conf; + ngx_http_cache_t *cache; + ngx_file_t file; ngx_pool_t *pool; diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 6b0e62efc..bb89336fe 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -192,7 +192,8 @@ ngx_log_debug(c->log, "NOPUSH"); if (err == NGX_EAGAIN || err == NGX_EINTR) { ngx_log_error(NGX_LOG_INFO, c->log, err, - "sendfile() sent only %qd bytes", sent); + "sendfile() sent only " OFF_T_FMT " bytes", + sent); } else { wev->error = 1; diff --git a/src/os/unix/ngx_solaris.h b/src/os/unix/ngx_solaris.h new file mode 100644 index 000000000..c0829b782 --- /dev/null +++ b/src/os/unix/ngx_solaris.h @@ -0,0 +1,8 @@ +#ifndef _NGX_SOLARIS_H_INCLUDED_ +#define _NGX_SOLARIS_H_INCLUDED_ + + +ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in); + + +#endif /* _NGX_SOLARIS_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h index 078d8d07c..233b46bf2 100644 --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -23,6 +23,7 @@ #include /* FIONBIO */ #include /* INFTIM */ #include +#include #include #include #include diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c new file mode 100644 index 000000000..8fe5cef1e --- /dev/null +++ b/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -0,0 +1,147 @@ + +#include +#include +#include + + +ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in) +{ + int fd; + char *prev; + off_t fprev; + size_t sent; + ssize_t n; + ngx_int_t eintr; + sendfilevec_t *sfv; + ngx_array_t vec; + ngx_event_t *wev; + ngx_chain_t *cl; + + wev = c->write; + + if (!wev->ready) { + return in; + } + + do { + fd = SFV_FD_SELF; + prev = NULL; + sfv = NULL; + eintr = 0; + sent = 0; + + /* create the sendfilevec and coalesce the neighbouring hunks */ + + for (cl = in; cl; cl = cl->next) { + if (ngx_hunk_special(cl->hunk)) { + continue; + } + + if (ngx_hunk_in_memory_only(cl->hunk)) { + fd = SFV_FD_SELF; + + if (prev == cl->hunk->pos) { + sfv->sfv_len += cl->hunk->last - cl->hunk->pos; + + } else { + ngx_test_null(sfv, ngx_push_array(&vec), NGX_CHAIN_ERROR); + sfv->sfv_fd = SFV_FD_SELF; + sfv->sfv_flag = 0; + sfv->sfv_off = cl->hunk->pos; + sfv->sfv_len = cl->hunk->last - cl->hunk->pos; + } + + prev = cl->hunk->last; + + } else { + prev = NULL; + + if (fd == cl->hunk->file->fd && fprev == cl->hunk->file_pos) { + sfv->sfv_len += cl->hunk->file_last - cl->hunk->file_pos; + + } else { + ngx_test_null(sfv, ngx_push_array(&vec), NGX_CHAIN_ERROR); + fd = cl->hunk->file->fd; + sfv->sfv_fd = fd; + sfv->sfv_flag = 0; + sfv->sfv_off = cl->hunk->file_pos; + sfv->sfv_len = cl->hunk->file_last - cl->hunk->file_pos; + } + + fprev = cl->hunk->file_last; + } + } + + n = sendfile(c->fd, vec->elts, vec->nelts, &sent); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + eintr = 1; + } + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_error(NGX_LOG_INFO, c->log, err, + "sendfilev() sent only " SIZE_T_FMT " bytes", + sent); + } else { + wev->error = 1; + ngx_log_error(NGX_LOG_CRIT, c->log, err, "sendfilev() failed"); + return NGX_CHAIN_ERROR; + } + } + +#if (NGX_DEBUG_WRITE_CHAIN) + ngx_log_debug(c->log, "sendfilev: %d " SIZE_T_FMT ", n _ sent); +#endif + + c->sent += sent; + + for (cl = in; cl; cl = cl->next) { + + if (ngx_hunk_special(cl->hunk)) { + continue; + } + + if (sent == 0) { + break; + } + + size = ngx_hunk_size(cl->hunk); + + if (sent >= size) { + sent -= size; + + if (cl->hunk->type & NGX_HUNK_IN_MEMORY) { + cl->hunk->pos = cl->hunk->last; + } + + if (cl->hunk->type & NGX_HUNK_FILE) { + cl->hunk->file_pos = cl->hunk->file_last; + } + + continue; + } + + if (cl->hunk->type & NGX_HUNK_IN_MEMORY) { + cl->hunk->pos += sent; + } + + if (cl->hunk->type & NGX_HUNK_FILE) { + cl->hunk->file_pos += sent; + } + + break; + } + + in = cl; + + } while (eintr); + + if (in) { + wev->ready = 0; + } + + return in; +}