nginx/src/os/unix/ngx_solaris_sendfilev_chain.c
Valentin Bartenev f00918eab3 Refactored ngx_solaris_sendfilev_chain().
Though ngx_solaris_sendfilev_chain() shouldn't suffer from the problem mentioned
in d1bde5c3c5d2 since currently IOV_MAX on Solaris is 16, but this follows the
change from 3d5717550371 in order to make the code look similar to other systems
and potentially eliminates the problem in the future.
2014-11-19 21:17:11 +03:00

206 lines
4.8 KiB
C

/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#if (NGX_TEST_BUILD_SOLARIS_SENDFILEV)
/* Solaris declarations */
typedef struct sendfilevec {
int sfv_fd;
u_int sfv_flag;
off_t sfv_off;
size_t sfv_len;
} sendfilevec_t;
#define SFV_FD_SELF -2
static ssize_t sendfilev(int fd, const struct sendfilevec *vec,
int sfvcnt, size_t *xferred)
{
return -1;
}
ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
#endif
#define NGX_SENDFILEVECS NGX_IOVS_PREALLOCATE
ngx_chain_t *
ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
{
int fd;
u_char *prev;
off_t size, send, prev_send, aligned, fprev;
size_t sent;
ssize_t n;
ngx_int_t eintr;
ngx_err_t err;
ngx_uint_t nsfv;
sendfilevec_t *sfv, sfvs[NGX_SENDFILEVECS];
ngx_event_t *wev;
ngx_chain_t *cl;
wev = c->write;
if (!wev->ready) {
return in;
}
if (!c->sendfile) {
return ngx_writev_chain(c, in, limit);
}
/* the maximum limit size is the maximum size_t value - the page size */
if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
}
send = 0;
for ( ;; ) {
fd = SFV_FD_SELF;
prev = NULL;
fprev = 0;
sfv = NULL;
eintr = 0;
sent = 0;
prev_send = send;
nsfv = 0;
/* create the sendfilevec and coalesce the neighbouring bufs */
for (cl = in; cl && send < limit; cl = cl->next) {
if (ngx_buf_special(cl->buf)) {
continue;
}
if (ngx_buf_in_memory_only(cl->buf)) {
fd = SFV_FD_SELF;
size = cl->buf->last - cl->buf->pos;
if (send + size > limit) {
size = limit - send;
}
if (prev == cl->buf->pos) {
sfv->sfv_len += (size_t) size;
} else {
if (nsfv == NGX_SENDFILEVECS) {
break;
}
sfv = &sfvs[nsfv++];
sfv->sfv_fd = SFV_FD_SELF;
sfv->sfv_flag = 0;
sfv->sfv_off = (off_t) (uintptr_t) cl->buf->pos;
sfv->sfv_len = (size_t) size;
}
prev = cl->buf->pos + (size_t) size;
send += size;
} else {
prev = NULL;
size = cl->buf->file_last - cl->buf->file_pos;
if (send + size > limit) {
size = limit - send;
aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
& ~((off_t) ngx_pagesize - 1);
if (aligned <= cl->buf->file_last) {
size = aligned - cl->buf->file_pos;
}
}
if (fd == cl->buf->file->fd && fprev == cl->buf->file_pos) {
sfv->sfv_len += (size_t) size;
} else {
if (nsfv == NGX_SENDFILEVECS) {
break;
}
sfv = &sfvs[nsfv++];
fd = cl->buf->file->fd;
sfv->sfv_fd = fd;
sfv->sfv_flag = 0;
sfv->sfv_off = cl->buf->file_pos;
sfv->sfv_len = (size_t) size;
}
fprev = cl->buf->file_pos + size;
send += size;
}
}
n = sendfilev(c->fd, sfvs, nsfv, &sent);
if (n == -1) {
err = ngx_errno;
switch (err) {
case NGX_EAGAIN:
break;
case NGX_EINTR:
eintr = 1;
break;
default:
wev->error = 1;
ngx_connection_error(c, err, "sendfilev() failed");
return NGX_CHAIN_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
"sendfilev() sent only %uz bytes", sent);
}
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"sendfilev: %z %z", n, sent);
c->sent += sent;
in = ngx_chain_update_sent(in, sent);
if (eintr) {
send = prev_send + sent;
continue;
}
if (send - prev_send != (off_t) sent) {
wev->ready = 0;
return in;
}
if (send >= limit || in == NULL) {
return in;
}
}
}