blob: 1c755e8dcecd0f0ea448a84c4de157680d81b29f [file] [log] [blame]
Igor Sysoev0e499db2003-11-27 07:45:22 +00001
Igor Sysoevd94049b2004-02-29 21:03:02 +00002/*
3 * Copyright (C) 2002-2004 Igor Sysoev, http://sysoev.ru/en/
4 */
5
6
Igor Sysoev0e499db2003-11-27 07:45:22 +00007#include <ngx_config.h>
8#include <ngx_core.h>
9#include <ngx_event.h>
10
11
12ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in)
13{
14 int fd;
Igor Sysoev10a543a2004-03-16 07:10:12 +000015 u_char *prev;
Igor Sysoev0e499db2003-11-27 07:45:22 +000016 off_t fprev;
Igor Sysoev764543e2003-11-27 19:01:37 +000017 size_t sent, size;
Igor Sysoev0e499db2003-11-27 07:45:22 +000018 ssize_t n;
19 ngx_int_t eintr;
Igor Sysoev764543e2003-11-27 19:01:37 +000020 ngx_err_t err;
Igor Sysoev0e499db2003-11-27 07:45:22 +000021 sendfilevec_t *sfv;
22 ngx_array_t vec;
23 ngx_event_t *wev;
Igor Sysoev8ae18a12004-02-18 15:45:21 +000024 ngx_chain_t *cl, *tail;
Igor Sysoev0e499db2003-11-27 07:45:22 +000025
26 wev = c->write;
27
28 if (!wev->ready) {
29 return in;
30 }
31
32 do {
33 fd = SFV_FD_SELF;
34 prev = NULL;
Igor Sysoev764543e2003-11-27 19:01:37 +000035 fprev = 0;
Igor Sysoev0e499db2003-11-27 07:45:22 +000036 sfv = NULL;
37 eintr = 0;
38 sent = 0;
39
Igor Sysoev764543e2003-11-27 19:01:37 +000040 ngx_init_array(vec, c->pool, 10, sizeof(sendfilevec_t),
41 NGX_CHAIN_ERROR);
42
Igor Sysoev0e499db2003-11-27 07:45:22 +000043 /* create the sendfilevec and coalesce the neighbouring hunks */
44
Igor Sysoev8ae18a12004-02-18 15:45:21 +000045 for (cl = in; cl && vec.nelts < IOV_MAX; cl = cl->next) {
Igor Sysoev0e499db2003-11-27 07:45:22 +000046 if (ngx_hunk_special(cl->hunk)) {
47 continue;
48 }
49
50 if (ngx_hunk_in_memory_only(cl->hunk)) {
51 fd = SFV_FD_SELF;
52
53 if (prev == cl->hunk->pos) {
54 sfv->sfv_len += cl->hunk->last - cl->hunk->pos;
55
56 } else {
57 ngx_test_null(sfv, ngx_push_array(&vec), NGX_CHAIN_ERROR);
58 sfv->sfv_fd = SFV_FD_SELF;
59 sfv->sfv_flag = 0;
Igor Sysoev764543e2003-11-27 19:01:37 +000060 sfv->sfv_off = (off_t) (uintptr_t) cl->hunk->pos;
Igor Sysoev0e499db2003-11-27 07:45:22 +000061 sfv->sfv_len = cl->hunk->last - cl->hunk->pos;
62 }
63
64 prev = cl->hunk->last;
65
66 } else {
67 prev = NULL;
68
69 if (fd == cl->hunk->file->fd && fprev == cl->hunk->file_pos) {
70 sfv->sfv_len += cl->hunk->file_last - cl->hunk->file_pos;
71
72 } else {
73 ngx_test_null(sfv, ngx_push_array(&vec), NGX_CHAIN_ERROR);
74 fd = cl->hunk->file->fd;
75 sfv->sfv_fd = fd;
76 sfv->sfv_flag = 0;
77 sfv->sfv_off = cl->hunk->file_pos;
78 sfv->sfv_len = cl->hunk->file_last - cl->hunk->file_pos;
79 }
80
81 fprev = cl->hunk->file_last;
82 }
83 }
84
Igor Sysoev8ae18a12004-02-18 15:45:21 +000085 /*
86 * the tail is the rest of the chain that exceeded a single
87 * sendfilev() capability, IOV_MAX in Solaris is only 16
88 */
89
90 tail = cl;
91
Igor Sysoev764543e2003-11-27 19:01:37 +000092 n = sendfilev(c->fd, vec.elts, vec.nelts, &sent);
Igor Sysoev0e499db2003-11-27 07:45:22 +000093
94 if (n == -1) {
95 err = ngx_errno;
96
Igor Sysoev0e499db2003-11-27 07:45:22 +000097 if (err == NGX_EAGAIN || err == NGX_EINTR) {
Igor Sysoev54498db2004-02-11 17:08:49 +000098 if (err == NGX_EINTR) {
99 eintr = 1;
100 }
101
102 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
Igor Sysoev0e499db2003-11-27 07:45:22 +0000103 "sendfilev() sent only " SIZE_T_FMT " bytes",
104 sent);
Igor Sysoev54498db2004-02-11 17:08:49 +0000105
Igor Sysoev0e499db2003-11-27 07:45:22 +0000106 } else {
107 wev->error = 1;
Igor Sysoev54498db2004-02-11 17:08:49 +0000108 ngx_connection_error(c, err, "sendfilev() failed");
Igor Sysoev0e499db2003-11-27 07:45:22 +0000109 return NGX_CHAIN_ERROR;
110 }
111 }
112
Igor Sysoev54498db2004-02-11 17:08:49 +0000113 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
114 "sendfilev: %d " SIZE_T_FMT, n, sent);
Igor Sysoev0e499db2003-11-27 07:45:22 +0000115
116 c->sent += sent;
117
118 for (cl = in; cl; cl = cl->next) {
119
120 if (ngx_hunk_special(cl->hunk)) {
121 continue;
122 }
123
124 if (sent == 0) {
125 break;
126 }
127
128 size = ngx_hunk_size(cl->hunk);
129
130 if (sent >= size) {
131 sent -= size;
132
133 if (cl->hunk->type & NGX_HUNK_IN_MEMORY) {
134 cl->hunk->pos = cl->hunk->last;
135 }
136
137 if (cl->hunk->type & NGX_HUNK_FILE) {
138 cl->hunk->file_pos = cl->hunk->file_last;
139 }
140
141 continue;
142 }
143
144 if (cl->hunk->type & NGX_HUNK_IN_MEMORY) {
145 cl->hunk->pos += sent;
146 }
147
148 if (cl->hunk->type & NGX_HUNK_FILE) {
149 cl->hunk->file_pos += sent;
150 }
151
152 break;
153 }
154
155 in = cl;
156
Igor Sysoev8ae18a12004-02-18 15:45:21 +0000157 /* "tail == in" means that a single sendfilev() is complete */
158
159 } while ((tail && tail == in) || eintr);
Igor Sysoev0e499db2003-11-27 07:45:22 +0000160
161 if (in) {
162 wev->ready = 0;
163 }
164
165 return in;
166}