Mercurial > hg > nginx
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) { |