comparison src/os/unix/ngx_darwin_sendfile_chain.c @ 5913:8e903522c17a

Introduced the ngx_output_chain_to_iovec() function. It deduplicates code of the send chain functions and uses only preallocated memory, which completely solves the problem mentioned in d1bde5c3c5d2.
author Valentin Bartenev <vbart@nginx.com>
date Tue, 07 Oct 2014 11:38:57 +0400
parents de68ed551bfb
children ac3f78219f85
comparison
equal deleted inserted replaced
5912:de68ed551bfb 5913:8e903522c17a
29 29
30 ngx_chain_t * 30 ngx_chain_t *
31 ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) 31 ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
32 { 32 {
33 int rc; 33 int rc;
34 u_char *prev;
35 off_t size, send, prev_send, aligned, sent, fprev; 34 off_t size, send, prev_send, aligned, sent, fprev;
36 off_t header_size, file_size; 35 off_t file_size;
37 ngx_uint_t eintr; 36 ngx_uint_t eintr;
38 ngx_err_t err; 37 ngx_err_t err;
39 ngx_buf_t *file; 38 ngx_buf_t *file;
40 ngx_array_t header, trailer;
41 ngx_event_t *wev; 39 ngx_event_t *wev;
42 ngx_chain_t *cl; 40 ngx_chain_t *cl;
41 ngx_iovec_t header, trailer;
43 struct sf_hdtr hdtr; 42 struct sf_hdtr hdtr;
44 struct iovec *iov;
45 struct iovec headers[NGX_IOVS_PREALLOCATE]; 43 struct iovec headers[NGX_IOVS_PREALLOCATE];
46 struct iovec trailers[NGX_IOVS_PREALLOCATE]; 44 struct iovec trailers[NGX_IOVS_PREALLOCATE];
47 45
48 wev = c->write; 46 wev = c->write;
49 47
68 limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; 66 limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
69 } 67 }
70 68
71 send = 0; 69 send = 0;
72 70
73 header.elts = headers; 71 header.iovs = headers;
74 header.size = sizeof(struct iovec);
75 header.nalloc = NGX_IOVS_PREALLOCATE; 72 header.nalloc = NGX_IOVS_PREALLOCATE;
76 header.pool = c->pool; 73
77 74 trailer.iovs = trailers;
78 trailer.elts = trailers;
79 trailer.size = sizeof(struct iovec);
80 trailer.nalloc = NGX_IOVS_PREALLOCATE; 75 trailer.nalloc = NGX_IOVS_PREALLOCATE;
81 trailer.pool = c->pool;
82 76
83 for ( ;; ) { 77 for ( ;; ) {
84 file = NULL; 78 file = NULL;
85 file_size = 0; 79 file_size = 0;
86 header_size = 0;
87 eintr = 0; 80 eintr = 0;
88 prev_send = send; 81 prev_send = send;
89 82
90 header.nelts = 0;
91 trailer.nelts = 0;
92
93 /* create the header iovec and coalesce the neighbouring bufs */ 83 /* create the header iovec and coalesce the neighbouring bufs */
94 84
95 prev = NULL; 85 cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log);
96 iov = NULL; 86
97 87 if (cl == NGX_CHAIN_ERROR) {
98 for (cl = in; cl && send < limit; cl = cl->next) { 88 return NGX_CHAIN_ERROR;
99 89 }
100 if (ngx_buf_special(cl->buf)) { 90
101 continue; 91 send += header.size;
102 }
103
104 if (!ngx_buf_in_memory_only(cl->buf)) {
105 break;
106 }
107
108 size = cl->buf->last - cl->buf->pos;
109
110 if (send + size > limit) {
111 size = limit - send;
112 }
113
114 if (prev == cl->buf->pos) {
115 iov->iov_len += (size_t) size;
116
117 } else {
118 if (header.nelts >= IOV_MAX) {
119 break;
120 }
121
122 iov = ngx_array_push(&header);
123 if (iov == NULL) {
124 return NGX_CHAIN_ERROR;
125 }
126
127 iov->iov_base = (void *) cl->buf->pos;
128 iov->iov_len = (size_t) size;
129 }
130
131 prev = cl->buf->pos + (size_t) size;
132 header_size += size;
133 send += size;
134 }
135
136 92
137 if (cl && cl->buf->in_file && send < limit) { 93 if (cl && cl->buf->in_file && send < limit) {
138 file = cl->buf; 94 file = cl->buf;
139 95
140 /* coalesce the neighbouring file bufs */ 96 /* coalesce the neighbouring file bufs */
163 && send < limit 119 && send < limit
164 && file->file->fd == cl->buf->file->fd 120 && file->file->fd == cl->buf->file->fd
165 && fprev == cl->buf->file_pos); 121 && fprev == cl->buf->file_pos);
166 } 122 }
167 123
168 if (file && header.nelts == 0) { 124 if (file && header.count == 0) {
169 125
170 /* create the trailer iovec and coalesce the neighbouring bufs */ 126 /* create the trailer iovec and coalesce the neighbouring bufs */
171 127
172 prev = NULL; 128 cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send, c->log);
173 iov = NULL; 129
174 130 if (cl == NGX_CHAIN_ERROR) {
175 while (cl && send < limit) { 131 return NGX_CHAIN_ERROR;
176 132 }
177 if (ngx_buf_special(cl->buf)) { 133
178 cl = cl->next; 134 send += trailer.size;
179 continue;
180 }
181
182 if (!ngx_buf_in_memory_only(cl->buf)) {
183 break;
184 }
185
186 size = cl->buf->last - cl->buf->pos;
187
188 if (send + size > limit) {
189 size = limit - send;
190 }
191
192 if (prev == cl->buf->pos) {
193 iov->iov_len += (size_t) size;
194
195 } else {
196 if (trailer.nelts >= IOV_MAX) {
197 break;
198 }
199
200 iov = ngx_array_push(&trailer);
201 if (iov == NULL) {
202 return NGX_CHAIN_ERROR;
203 }
204
205 iov->iov_base = (void *) cl->buf->pos;
206 iov->iov_len = (size_t) size;
207 }
208
209 prev = cl->buf->pos + (size_t) size;
210 send += size;
211 cl = cl->next;
212 }
213 } 135 }
214 136
215 if (file) { 137 if (file) {
216 138
217 /* 139 /*
218 * sendfile() returns EINVAL if sf_hdtr's count is 0, 140 * sendfile() returns EINVAL if sf_hdtr's count is 0,
219 * but corresponding pointer is not NULL 141 * but corresponding pointer is not NULL
220 */ 142 */
221 143
222 hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL; 144 hdtr.headers = header.count ? header.iovs : NULL;
223 hdtr.hdr_cnt = header.nelts; 145 hdtr.hdr_cnt = header.count;
224 hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL; 146 hdtr.trailers = trailer.count ? trailer.iovs : NULL;
225 hdtr.trl_cnt = trailer.nelts; 147 hdtr.trl_cnt = trailer.count;
226 148
227 sent = header_size + file_size; 149 sent = header.size + file_size;
228 150
229 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, 151 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
230 "sendfile: @%O %O h:%O", 152 "sendfile: @%O %O h:%uz",
231 file->file_pos, sent, header_size); 153 file->file_pos, sent, header.size);
232 154
233 rc = sendfile(file->file->fd, c->fd, file->file_pos, 155 rc = sendfile(file->file->fd, c->fd, file->file_pos,
234 &sent, &hdtr, 0); 156 &sent, &hdtr, 0);
235 157
236 if (rc == -1) { 158 if (rc == -1) {
269 return NGX_CHAIN_ERROR; 191 return NGX_CHAIN_ERROR;
270 } 192 }
271 193
272 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, 194 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
273 "sendfile: %d, @%O %O:%O", 195 "sendfile: %d, @%O %O:%O",
274 rc, file->file_pos, sent, file_size + header_size); 196 rc, file->file_pos, sent, file_size + header.size);
275 197
276 } else { 198 } else {
277 rc = writev(c->fd, header.elts, header.nelts); 199 rc = writev(c->fd, header.iovs, header.count);
278 200
279 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, 201 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
280 "writev: %d of %O", rc, header_size); 202 "writev: %d of %uz", rc, header.size);
281 203
282 if (rc == -1) { 204 if (rc == -1) {
283 err = ngx_errno; 205 err = ngx_errno;
284 206
285 switch (err) { 207 switch (err) {