diff options
Diffstat (limited to 'src/nxt_solaris_sendfilev.c')
-rw-r--r-- | src/nxt_solaris_sendfilev.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/nxt_solaris_sendfilev.c b/src/nxt_solaris_sendfilev.c new file mode 100644 index 00000000..fdd803dc --- /dev/null +++ b/src/nxt_solaris_sendfilev.c @@ -0,0 +1,170 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +/* + * sendfilev() has been introduced in Solaris 8 (7/01). + * According to sendfilev(3EXT) it can write to: + * + * a file descriptor to a regular file or to a AF_NCA, AF_INET, or + * AF_INET6 family type SOCK_STREAM socket that is open for writing. + */ + +ssize_t nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, + size_t limit); +static size_t nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, + int32_t *nsfv, nxt_bool_t *sync, size_t limit); + + +ssize_t +nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, + size_t limit) +{ + size_t sent; + ssize_t n; + int32_t nsfv; + nxt_err_t err; + nxt_off_t size; + nxt_bool_t sync; + sendfilevec_t sfv[NXT_IOBUF_MAX]; + + if (c->sendfile == 0) { + /* AF_UNIX does not support sendfilev(). */ + return nxt_event_conn_io_sendbuf(c, b, limit); + } + + sync = 0; + + size = nxt_solaris_buf_coalesce(b, sfv, &nsfv, &sync, limit); + + nxt_log_debug(c->socket.log, "sendfilev(%d, %D)", c->socket.fd, nsfv); + + if (nsfv == 0 && sync) { + return 0; + } + + sent = 0; + n = sendfilev(c->socket.fd, sfv, nsfv, &sent); + + err = (n == -1) ? nxt_errno : 0; + + nxt_log_debug(c->socket.log, "sendfilev(): %d sent:%uz", n, sent); + + if (n == -1) { + switch (err) { + + case NXT_EAGAIN: + c->socket.write_ready = 0; + break; + + case NXT_EINTR: + break; + + default: + c->socket.error = err; + nxt_log_error(nxt_socket_error_level(err, c->socket.log_error), + c->socket.log, "sendfilev(%d, %D) failed %E", + c->socket.fd, nsfv, err); + + return NXT_ERROR; + } + + nxt_log_debug(c->socket.log, "sendfilev() %E", err); + + return sent; + } + + if ((nxt_off_t) sent < size) { + c->socket.write_ready = 0; + } + + return sent; +} + + +static size_t +nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, int32_t *nsfv, + nxt_bool_t *sync, size_t limit) +{ + size_t size, total; + nxt_fd_t fd, last_fd; + nxt_int_t i; + nxt_off_t pos, last_pos; + + i = -1; + last_fd = -1; + last_pos = 0; + total = 0; + + for (total = 0; b != NULL && total < limit; b = b->next) { + + if (nxt_buf_is_file(b)) { + + fd = b->file->fd; + pos = b->file_pos; + size = b->file_end - pos; + + if (size == 0) { + continue; + } + + if (total + size > limit) { + size = limit - total; + } + + } else if (nxt_buf_is_mem(b)) { + + fd = SFV_FD_SELF; + pos = (uintptr_t) b->mem.pos; + size = b->mem.free - b->mem.pos; + + if (size == 0) { + continue; + } + + if (total + size > limit) { + size = limit - total; + } + + } else { + *sync = 1; + continue; + } + + if (size == 0) { + break; + } + + if (fd != last_fd || pos != last_pos) { + + if (++i >= NXT_IOBUF_MAX) { + goto done; + } + + sfv[i].sfv_fd = fd; + sfv[i].sfv_flag = 0; + sfv[i].sfv_off = pos; + sfv[i].sfv_len = size; + + } else { + sfv[i].sfv_len += size; + } + + total += size; + last_pos = pos + size; + last_fd = fd; + } + + i++; + +done: + + *nsfv = i; + + return total; +} |