Mercurial > hg > nginx
comparison src/os/unix/ngx_writev_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 | 2c64b69daec5 |
comparison
equal
deleted
inserted
replaced
5912:de68ed551bfb | 5913:8e903522c17a |
---|---|
11 | 11 |
12 | 12 |
13 ngx_chain_t * | 13 ngx_chain_t * |
14 ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) | 14 ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) |
15 { | 15 { |
16 u_char *prev; | 16 ssize_t n, sent; |
17 ssize_t n, size, sent; | |
18 off_t send, prev_send; | 17 off_t send, prev_send; |
19 ngx_uint_t eintr; | 18 ngx_uint_t eintr; |
20 ngx_err_t err; | 19 ngx_err_t err; |
21 ngx_array_t vec; | |
22 ngx_chain_t *cl; | 20 ngx_chain_t *cl; |
23 ngx_event_t *wev; | 21 ngx_event_t *wev; |
24 struct iovec *iov, iovs[NGX_IOVS_PREALLOCATE]; | 22 ngx_iovec_t vec; |
23 struct iovec iovs[NGX_IOVS_PREALLOCATE]; | |
25 | 24 |
26 wev = c->write; | 25 wev = c->write; |
27 | 26 |
28 if (!wev->ready) { | 27 if (!wev->ready) { |
29 return in; | 28 return in; |
46 limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; | 45 limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; |
47 } | 46 } |
48 | 47 |
49 send = 0; | 48 send = 0; |
50 | 49 |
51 vec.elts = iovs; | 50 vec.iovs = iovs; |
52 vec.size = sizeof(struct iovec); | |
53 vec.nalloc = NGX_IOVS_PREALLOCATE; | 51 vec.nalloc = NGX_IOVS_PREALLOCATE; |
54 vec.pool = c->pool; | |
55 | 52 |
56 for ( ;; ) { | 53 for ( ;; ) { |
57 prev = NULL; | |
58 iov = NULL; | |
59 eintr = 0; | 54 eintr = 0; |
60 prev_send = send; | 55 prev_send = send; |
61 | 56 |
62 vec.nelts = 0; | |
63 | |
64 /* create the iovec and coalesce the neighbouring bufs */ | 57 /* create the iovec and coalesce the neighbouring bufs */ |
65 | 58 |
66 for (cl = in; cl && send < limit; cl = cl->next) { | 59 cl = ngx_output_chain_to_iovec(&vec, in, limit - send, c->log); |
67 | 60 |
68 if (ngx_buf_special(cl->buf)) { | 61 if (cl == NGX_CHAIN_ERROR) { |
69 continue; | 62 return NGX_CHAIN_ERROR; |
70 } | 63 } |
71 | 64 |
72 #if 1 | 65 if (cl && cl->buf->in_file) { |
73 if (!ngx_buf_in_memory(cl->buf)) { | 66 ngx_log_error(NGX_LOG_ALERT, c->log, 0, |
74 ngx_debug_point(); | 67 "file buf in writev " |
75 } | 68 "t:%d r:%d f:%d %p %p-%p %p %O-%O", |
76 #endif | 69 cl->buf->temporary, |
77 | 70 cl->buf->recycled, |
78 size = cl->buf->last - cl->buf->pos; | 71 cl->buf->in_file, |
79 | 72 cl->buf->start, |
80 if (send + size > limit) { | 73 cl->buf->pos, |
81 size = (ssize_t) (limit - send); | 74 cl->buf->last, |
82 } | 75 cl->buf->file, |
83 | 76 cl->buf->file_pos, |
84 if (prev == cl->buf->pos) { | 77 cl->buf->file_last); |
85 iov->iov_len += size; | 78 |
86 | 79 ngx_debug_point(); |
87 } else { | 80 |
88 if (vec.nelts >= IOV_MAX) { | 81 return NGX_CHAIN_ERROR; |
89 break; | 82 } |
90 } | 83 |
91 | 84 send += vec.size; |
92 iov = ngx_array_push(&vec); | 85 |
93 if (iov == NULL) { | 86 n = writev(c->fd, vec.iovs, vec.count); |
94 return NGX_CHAIN_ERROR; | |
95 } | |
96 | |
97 iov->iov_base = (void *) cl->buf->pos; | |
98 iov->iov_len = size; | |
99 } | |
100 | |
101 prev = cl->buf->pos + size; | |
102 send += size; | |
103 } | |
104 | |
105 n = writev(c->fd, vec.elts, vec.nelts); | |
106 | 87 |
107 if (n == -1) { | 88 if (n == -1) { |
108 err = ngx_errno; | 89 err = ngx_errno; |
109 | 90 |
110 switch (err) { | 91 switch (err) { |
146 if (send >= limit || in == NULL) { | 127 if (send >= limit || in == NULL) { |
147 return in; | 128 return in; |
148 } | 129 } |
149 } | 130 } |
150 } | 131 } |
132 | |
133 | |
134 ngx_chain_t * | |
135 ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, size_t limit, | |
136 ngx_log_t *log) | |
137 { | |
138 size_t total, size; | |
139 u_char *prev; | |
140 ngx_uint_t n; | |
141 struct iovec *iov; | |
142 | |
143 iov = NULL; | |
144 prev = NULL; | |
145 total = 0; | |
146 n = 0; | |
147 | |
148 for ( /* void */ ; in && total < limit; in = in->next) { | |
149 | |
150 if (ngx_buf_special(in->buf)) { | |
151 continue; | |
152 } | |
153 | |
154 if (in->buf->in_file) { | |
155 break; | |
156 } | |
157 | |
158 if (!ngx_buf_in_memory(in->buf)) { | |
159 ngx_log_error(NGX_LOG_ALERT, log, 0, | |
160 "bad buf in output chain " | |
161 "t:%d r:%d f:%d %p %p-%p %p %O-%O", | |
162 in->buf->temporary, | |
163 in->buf->recycled, | |
164 in->buf->in_file, | |
165 in->buf->start, | |
166 in->buf->pos, | |
167 in->buf->last, | |
168 in->buf->file, | |
169 in->buf->file_pos, | |
170 in->buf->file_last); | |
171 | |
172 ngx_debug_point(); | |
173 | |
174 return NGX_CHAIN_ERROR; | |
175 } | |
176 | |
177 size = in->buf->last - in->buf->pos; | |
178 | |
179 if (size > limit - total) { | |
180 size = limit - total; | |
181 } | |
182 | |
183 if (prev == in->buf->pos) { | |
184 iov->iov_len += size; | |
185 | |
186 } else { | |
187 if (n == vec->nalloc) { | |
188 break; | |
189 } | |
190 | |
191 iov = &vec->iovs[n++]; | |
192 | |
193 iov->iov_base = (void *) in->buf->pos; | |
194 iov->iov_len = size; | |
195 } | |
196 | |
197 prev = in->buf->pos + size; | |
198 total += size; | |
199 } | |
200 | |
201 vec->count = n; | |
202 vec->size = total; | |
203 | |
204 return in; | |
205 } |