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) {