Mercurial > hg > nginx
comparison src/os/unix/ngx_linux_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 |
---|---|
30 ngx_chain_t * | 30 ngx_chain_t * |
31 ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) | 31 ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) |
32 { | 32 { |
33 int rc, tcp_nodelay; | 33 int rc, tcp_nodelay; |
34 off_t size, send, prev_send, aligned, sent, fprev; | 34 off_t size, send, prev_send, aligned, sent, fprev; |
35 u_char *prev; | |
36 size_t file_size; | 35 size_t file_size; |
37 ngx_err_t err; | 36 ngx_err_t err; |
38 ngx_buf_t *file; | 37 ngx_buf_t *file; |
39 ngx_uint_t eintr; | 38 ngx_uint_t eintr; |
40 ngx_array_t header; | |
41 ngx_event_t *wev; | 39 ngx_event_t *wev; |
42 ngx_chain_t *cl; | 40 ngx_chain_t *cl; |
43 struct iovec *iov, headers[NGX_IOVS_PREALLOCATE]; | 41 ngx_iovec_t header; |
42 struct iovec headers[NGX_IOVS_PREALLOCATE]; | |
44 #if (NGX_HAVE_SENDFILE64) | 43 #if (NGX_HAVE_SENDFILE64) |
45 off_t offset; | 44 off_t offset; |
46 #else | 45 #else |
47 int32_t offset; | 46 int32_t offset; |
48 #endif | 47 #endif |
61 } | 60 } |
62 | 61 |
63 | 62 |
64 send = 0; | 63 send = 0; |
65 | 64 |
66 header.elts = headers; | 65 header.iovs = headers; |
67 header.size = sizeof(struct iovec); | |
68 header.nalloc = NGX_IOVS_PREALLOCATE; | 66 header.nalloc = NGX_IOVS_PREALLOCATE; |
69 header.pool = c->pool; | |
70 | 67 |
71 for ( ;; ) { | 68 for ( ;; ) { |
72 file = NULL; | 69 file = NULL; |
73 file_size = 0; | 70 file_size = 0; |
74 eintr = 0; | 71 eintr = 0; |
75 prev_send = send; | 72 prev_send = send; |
76 | 73 |
77 header.nelts = 0; | |
78 | |
79 prev = NULL; | |
80 iov = NULL; | |
81 | |
82 /* create the iovec and coalesce the neighbouring bufs */ | 74 /* create the iovec and coalesce the neighbouring bufs */ |
83 | 75 |
84 for (cl = in; cl && send < limit; cl = cl->next) { | 76 cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); |
85 | 77 |
86 if (ngx_buf_special(cl->buf)) { | 78 if (cl == NGX_CHAIN_ERROR) { |
87 continue; | 79 return NGX_CHAIN_ERROR; |
88 } | 80 } |
89 | 81 |
90 #if 1 | 82 send += header.size; |
91 if (!ngx_buf_in_memory(cl->buf) && !cl->buf->in_file) { | |
92 ngx_log_error(NGX_LOG_ALERT, c->log, 0, | |
93 "zero size buf in sendfile " | |
94 "t:%d r:%d f:%d %p %p-%p %p %O-%O", | |
95 cl->buf->temporary, | |
96 cl->buf->recycled, | |
97 cl->buf->in_file, | |
98 cl->buf->start, | |
99 cl->buf->pos, | |
100 cl->buf->last, | |
101 cl->buf->file, | |
102 cl->buf->file_pos, | |
103 cl->buf->file_last); | |
104 | |
105 ngx_debug_point(); | |
106 | |
107 return NGX_CHAIN_ERROR; | |
108 } | |
109 #endif | |
110 | |
111 if (!ngx_buf_in_memory_only(cl->buf)) { | |
112 break; | |
113 } | |
114 | |
115 size = cl->buf->last - cl->buf->pos; | |
116 | |
117 if (send + size > limit) { | |
118 size = limit - send; | |
119 } | |
120 | |
121 if (prev == cl->buf->pos) { | |
122 iov->iov_len += (size_t) size; | |
123 | |
124 } else { | |
125 if (header.nelts >= IOV_MAX) { | |
126 break; | |
127 } | |
128 | |
129 iov = ngx_array_push(&header); | |
130 if (iov == NULL) { | |
131 return NGX_CHAIN_ERROR; | |
132 } | |
133 | |
134 iov->iov_base = (void *) cl->buf->pos; | |
135 iov->iov_len = (size_t) size; | |
136 } | |
137 | |
138 prev = cl->buf->pos + (size_t) size; | |
139 send += size; | |
140 } | |
141 | 83 |
142 /* set TCP_CORK if there is a header before a file */ | 84 /* set TCP_CORK if there is a header before a file */ |
143 | 85 |
144 if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET | 86 if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET |
145 && header.nelts != 0 | 87 && header.count != 0 |
146 && cl | 88 && cl |
147 && cl->buf->in_file) | 89 && cl->buf->in_file) |
148 { | 90 { |
149 /* the TCP_CORK and TCP_NODELAY are mutually exclusive */ | 91 /* the TCP_CORK and TCP_NODELAY are mutually exclusive */ |
150 | 92 |
204 } | 146 } |
205 } | 147 } |
206 | 148 |
207 /* get the file buf */ | 149 /* get the file buf */ |
208 | 150 |
209 if (header.nelts == 0 && cl && cl->buf->in_file && send < limit) { | 151 if (header.count == 0 && cl && cl->buf->in_file && send < limit) { |
210 file = cl->buf; | 152 file = cl->buf; |
211 | 153 |
212 /* coalesce the neighbouring file bufs */ | 154 /* coalesce the neighbouring file bufs */ |
213 | 155 |
214 do { | 156 do { |
281 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | 223 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, |
282 "sendfile: %d, @%O %O:%uz", | 224 "sendfile: %d, @%O %O:%uz", |
283 rc, file->file_pos, sent, file_size); | 225 rc, file->file_pos, sent, file_size); |
284 | 226 |
285 } else { | 227 } else { |
286 rc = writev(c->fd, header.elts, header.nelts); | 228 rc = writev(c->fd, header.iovs, header.count); |
287 | 229 |
288 if (rc == -1) { | 230 if (rc == -1) { |
289 err = ngx_errno; | 231 err = ngx_errno; |
290 | 232 |
291 switch (err) { | 233 switch (err) { |