summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_solaris_sendfilev.c
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2017-01-17 20:00:00 +0300
committerIgor Sysoev <igor@sysoev.ru>2017-01-17 20:00:00 +0300
commit16cbf3c076a0aca6d47adaf3f719493674cf2363 (patch)
treee6530480020f62a2bdbf249988ec3e2a751d3927 /src/nxt_solaris_sendfilev.c
downloadunit-16cbf3c076a0aca6d47adaf3f719493674cf2363.tar.gz
unit-16cbf3c076a0aca6d47adaf3f719493674cf2363.tar.bz2
Initial version.
Diffstat (limited to 'src/nxt_solaris_sendfilev.c')
-rw-r--r--src/nxt_solaris_sendfilev.c170
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;
+}