Mercurial > hg > nginx
comparison src/os/unix/ngx_freebsd_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 |
---|---|
31 | 31 |
32 ngx_chain_t * | 32 ngx_chain_t * |
33 ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) | 33 ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) |
34 { | 34 { |
35 int rc, flags; | 35 int rc, flags; |
36 u_char *prev; | |
37 off_t size, send, prev_send, aligned, sent, fprev; | 36 off_t size, send, prev_send, aligned, sent, fprev; |
38 size_t header_size, file_size; | 37 size_t file_size; |
39 ngx_uint_t eintr, eagain; | 38 ngx_uint_t eintr, eagain; |
40 ngx_err_t err; | 39 ngx_err_t err; |
41 ngx_buf_t *file; | 40 ngx_buf_t *file; |
42 ngx_array_t header, trailer; | |
43 ngx_event_t *wev; | 41 ngx_event_t *wev; |
44 ngx_chain_t *cl; | 42 ngx_chain_t *cl; |
43 ngx_iovec_t header, trailer; | |
45 struct sf_hdtr hdtr; | 44 struct sf_hdtr hdtr; |
46 struct iovec *iov; | |
47 struct iovec headers[NGX_IOVS_PREALLOCATE]; | 45 struct iovec headers[NGX_IOVS_PREALLOCATE]; |
48 struct iovec trailers[NGX_IOVS_PREALLOCATE]; | 46 struct iovec trailers[NGX_IOVS_PREALLOCATE]; |
49 | 47 |
50 wev = c->write; | 48 wev = c->write; |
51 | 49 |
72 | 70 |
73 send = 0; | 71 send = 0; |
74 eagain = 0; | 72 eagain = 0; |
75 flags = 0; | 73 flags = 0; |
76 | 74 |
77 header.elts = headers; | 75 header.iovs = headers; |
78 header.size = sizeof(struct iovec); | |
79 header.nalloc = NGX_IOVS_PREALLOCATE; | 76 header.nalloc = NGX_IOVS_PREALLOCATE; |
80 header.pool = c->pool; | 77 |
81 | 78 trailer.iovs = trailers; |
82 trailer.elts = trailers; | |
83 trailer.size = sizeof(struct iovec); | |
84 trailer.nalloc = NGX_IOVS_PREALLOCATE; | 79 trailer.nalloc = NGX_IOVS_PREALLOCATE; |
85 trailer.pool = c->pool; | |
86 | 80 |
87 for ( ;; ) { | 81 for ( ;; ) { |
88 file = NULL; | 82 file = NULL; |
89 file_size = 0; | 83 file_size = 0; |
90 header_size = 0; | |
91 eintr = 0; | 84 eintr = 0; |
92 prev_send = send; | 85 prev_send = send; |
93 | 86 |
94 header.nelts = 0; | |
95 trailer.nelts = 0; | |
96 | |
97 /* create the header iovec and coalesce the neighbouring bufs */ | 87 /* create the header iovec and coalesce the neighbouring bufs */ |
98 | 88 |
99 prev = NULL; | 89 cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); |
100 iov = NULL; | 90 |
101 | 91 if (cl == NGX_CHAIN_ERROR) { |
102 for (cl = in; cl && send < limit; cl = cl->next) { | 92 return NGX_CHAIN_ERROR; |
103 | 93 } |
104 if (ngx_buf_special(cl->buf)) { | 94 |
105 continue; | 95 send += header.size; |
106 } | |
107 | |
108 if (!ngx_buf_in_memory_only(cl->buf)) { | |
109 break; | |
110 } | |
111 | |
112 size = cl->buf->last - cl->buf->pos; | |
113 | |
114 if (send + size > limit) { | |
115 size = limit - send; | |
116 } | |
117 | |
118 if (prev == cl->buf->pos) { | |
119 iov->iov_len += (size_t) size; | |
120 | |
121 } else { | |
122 if (header.nelts >= IOV_MAX){ | |
123 break; | |
124 } | |
125 | |
126 iov = ngx_array_push(&header); | |
127 if (iov == NULL) { | |
128 return NGX_CHAIN_ERROR; | |
129 } | |
130 | |
131 iov->iov_base = (void *) cl->buf->pos; | |
132 iov->iov_len = (size_t) size; | |
133 } | |
134 | |
135 prev = cl->buf->pos + (size_t) size; | |
136 header_size += (size_t) size; | |
137 send += size; | |
138 } | |
139 | |
140 | 96 |
141 if (cl && cl->buf->in_file && send < limit) { | 97 if (cl && cl->buf->in_file && send < limit) { |
142 file = cl->buf; | 98 file = cl->buf; |
143 | 99 |
144 /* coalesce the neighbouring file bufs */ | 100 /* coalesce the neighbouring file bufs */ |
172 | 128 |
173 if (file) { | 129 if (file) { |
174 | 130 |
175 /* create the trailer iovec and coalesce the neighbouring bufs */ | 131 /* create the trailer iovec and coalesce the neighbouring bufs */ |
176 | 132 |
177 prev = NULL; | 133 cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send, c->log); |
178 iov = NULL; | 134 |
179 | 135 if (cl == NGX_CHAIN_ERROR) { |
180 while (cl && send < limit) { | 136 return NGX_CHAIN_ERROR; |
181 | 137 } |
182 if (ngx_buf_special(cl->buf)) { | 138 |
183 cl = cl->next; | 139 send += trailer.size; |
184 continue; | |
185 } | |
186 | |
187 if (!ngx_buf_in_memory_only(cl->buf)) { | |
188 break; | |
189 } | |
190 | |
191 size = cl->buf->last - cl->buf->pos; | |
192 | |
193 if (send + size > limit) { | |
194 size = limit - send; | |
195 } | |
196 | |
197 if (prev == cl->buf->pos) { | |
198 iov->iov_len += (size_t) size; | |
199 | |
200 } else { | |
201 if (trailer.nelts >= IOV_MAX){ | |
202 break; | |
203 } | |
204 | |
205 iov = ngx_array_push(&trailer); | |
206 if (iov == NULL) { | |
207 return NGX_CHAIN_ERROR; | |
208 } | |
209 | |
210 iov->iov_base = (void *) cl->buf->pos; | |
211 iov->iov_len = (size_t) size; | |
212 } | |
213 | |
214 prev = cl->buf->pos + (size_t) size; | |
215 send += size; | |
216 cl = cl->next; | |
217 } | |
218 } | 140 } |
219 | 141 |
220 if (file) { | 142 if (file) { |
221 | 143 |
222 if (ngx_freebsd_use_tcp_nopush | 144 if (ngx_freebsd_use_tcp_nopush |
248 /* | 170 /* |
249 * sendfile() does unneeded work if sf_hdtr's count is 0, | 171 * sendfile() does unneeded work if sf_hdtr's count is 0, |
250 * but corresponding pointer is not NULL | 172 * but corresponding pointer is not NULL |
251 */ | 173 */ |
252 | 174 |
253 hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL; | 175 hdtr.headers = header.count ? header.iovs : NULL; |
254 hdtr.hdr_cnt = header.nelts; | 176 hdtr.hdr_cnt = header.count; |
255 hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL; | 177 hdtr.trailers = trailer.count ? trailer.iovs : NULL; |
256 hdtr.trl_cnt = trailer.nelts; | 178 hdtr.trl_cnt = trailer.count; |
257 | 179 |
258 /* | 180 /* |
259 * the "nbytes bug" of the old sendfile() syscall: | 181 * the "nbytes bug" of the old sendfile() syscall: |
260 * http://bugs.freebsd.org/33771 | 182 * http://bugs.freebsd.org/33771 |
261 */ | 183 */ |
262 | 184 |
263 if (!ngx_freebsd_sendfile_nbytes_bug) { | 185 if (!ngx_freebsd_sendfile_nbytes_bug) { |
264 header_size = 0; | 186 header.size = 0; |
265 } | 187 } |
266 | 188 |
267 sent = 0; | 189 sent = 0; |
268 | 190 |
269 #if (NGX_HAVE_AIO_SENDFILE) | 191 #if (NGX_HAVE_AIO_SENDFILE) |
270 flags = c->aio_sendfile ? SF_NODISKIO : 0; | 192 flags = c->aio_sendfile ? SF_NODISKIO : 0; |
271 #endif | 193 #endif |
272 | 194 |
273 rc = sendfile(file->file->fd, c->fd, file->file_pos, | 195 rc = sendfile(file->file->fd, c->fd, file->file_pos, |
274 file_size + header_size, &hdtr, &sent, flags); | 196 file_size + header.size, &hdtr, &sent, flags); |
275 | 197 |
276 if (rc == -1) { | 198 if (rc == -1) { |
277 err = ngx_errno; | 199 err = ngx_errno; |
278 | 200 |
279 switch (err) { | 201 switch (err) { |
320 return NGX_CHAIN_ERROR; | 242 return NGX_CHAIN_ERROR; |
321 } | 243 } |
322 | 244 |
323 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | 245 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, |
324 "sendfile: %d, @%O %O:%uz", | 246 "sendfile: %d, @%O %O:%uz", |
325 rc, file->file_pos, sent, file_size + header_size); | 247 rc, file->file_pos, sent, file_size + header.size); |
326 | 248 |
327 } else { | 249 } else { |
328 rc = writev(c->fd, header.elts, header.nelts); | 250 rc = writev(c->fd, header.iovs, header.count); |
329 | 251 |
330 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 252 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
331 "writev: %d of %uz", rc, header_size); | 253 "writev: %d of %uz", rc, header.size); |
332 | 254 |
333 if (rc == -1) { | 255 if (rc == -1) { |
334 err = ngx_errno; | 256 err = ngx_errno; |
335 | 257 |
336 switch (err) { | 258 switch (err) { |