Mercurial > hg > nginx
comparison src/os/unix/ngx_freebsd_sendfile_chain.c @ 152:fb48bf4fea1c
nginx-0.0.1-2003-10-21-11:47:21 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 21 Oct 2003 07:47:21 +0000 |
parents | ef8c87afcfc5 |
children | c71aeb75c071 |
comparison
equal
deleted
inserted
replaced
151:2d9e4a8b6d11 | 152:fb48bf4fea1c |
---|---|
12 * with the part of the file in one packet. So we use TCP_NOPUSH (similar | 12 * with the part of the file in one packet. So we use TCP_NOPUSH (similar |
13 * to Linux's TCP_CORK) to postpone the sending - it not only sends the header | 13 * to Linux's TCP_CORK) to postpone the sending - it not only sends the header |
14 * and the first part of the file in one packet but also sends 4K pages | 14 * and the first part of the file in one packet but also sends 4K pages |
15 * in the full packets. | 15 * in the full packets. |
16 * | 16 * |
17 * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush | 17 * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush the pending |
18 * the pending data that less than MSS so the data is sent with 5 second delay. | 18 * data that less than MSS so the data can be sent with 5 second delay. |
19 * We do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used | 19 * We do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used |
20 * for non-keepalive HTTP connections. | 20 * for non-keepalive HTTP connections. |
21 */ | 21 */ |
22 | 22 |
23 | 23 |
24 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) | 24 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) |
25 { | 25 { |
26 int rc, eintr; | 26 int rc, eintr, eagain; |
27 char *prev; | 27 char *prev; |
28 ssize_t hsize, size; | 28 ssize_t hsize, fsize, size; |
29 off_t sent; | 29 off_t sent, fprev; |
30 struct iovec *iov; | 30 struct iovec *iov; |
31 struct sf_hdtr hdtr; | 31 struct sf_hdtr hdtr; |
32 ngx_err_t err; | 32 ngx_err_t err; |
33 ngx_array_t header, trailer; | 33 ngx_array_t header, trailer; |
34 ngx_hunk_t *file; | 34 ngx_hunk_t *file; |
39 } | 39 } |
40 | 40 |
41 do { | 41 do { |
42 ce = in; | 42 ce = in; |
43 file = NULL; | 43 file = NULL; |
44 fsize = 0; | |
44 hsize = 0; | 45 hsize = 0; |
45 eintr = 0; | 46 eintr = 0; |
47 eagain = 0; | |
46 | 48 |
47 ngx_init_array(header, c->pool, 10, sizeof(struct iovec), | 49 ngx_init_array(header, c->pool, 10, sizeof(struct iovec), |
48 NGX_CHAIN_ERROR); | 50 NGX_CHAIN_ERROR); |
49 ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), | 51 ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), |
50 NGX_CHAIN_ERROR); | 52 NGX_CHAIN_ERROR); |
75 } | 77 } |
76 | 78 |
77 hsize += ce->hunk->last - ce->hunk->pos; | 79 hsize += ce->hunk->last - ce->hunk->pos; |
78 } | 80 } |
79 | 81 |
80 /* TODO: coalesce the neighbouring file hunks */ | 82 /* get the file hunk */ |
81 | 83 |
82 if (ce && (ce->hunk->type & NGX_HUNK_FILE)) { | 84 if (ce && (ce->hunk->type & NGX_HUNK_FILE)) { |
83 file = ce->hunk; | 85 file = ce->hunk; |
84 ce = ce->next; | 86 ce = ce->next; |
87 fsize = (size_t) (file->file_last - file->file_pos); | |
88 fprev = file->file_last; | |
89 | |
90 /* coalesce the neighbouring file hunks */ | |
91 | |
92 while (ce && (ce->hunk->type & NGX_HUNK_FILE)) { | |
93 if (file->file->fd != ce->hunk->file->fd | |
94 || fprev != ce->hunk->file_pos) | |
95 { | |
96 break; | |
97 } | |
98 | |
99 fsize += (size_t) (ce->hunk->file_last - ce->hunk->file_pos); | |
100 fprev = ce->hunk->file_last; | |
101 ce = ce->next; | |
102 } | |
85 } | 103 } |
86 | 104 |
87 /* create the iovec and coalesce the neighbouring chain entries */ | 105 /* create the iovec and coalesce the neighbouring chain entries */ |
88 | 106 |
89 prev = NULL; | 107 prev = NULL; |
108 iov->iov_len = ce->hunk->last - ce->hunk->pos; | 126 iov->iov_len = ce->hunk->last - ce->hunk->pos; |
109 prev = ce->hunk->last; | 127 prev = ce->hunk->last; |
110 } | 128 } |
111 } | 129 } |
112 | 130 |
131 /* | |
132 * the tail is the rest of the chain that exceeded | |
133 * a single sendfile() capability | |
134 */ | |
135 | |
113 tail = ce; | 136 tail = ce; |
114 | 137 |
115 if (file) { | 138 if (file) { |
116 | 139 |
117 if (ngx_freebsd_use_tcp_nopush && !c->tcp_nopush) { | 140 if (ngx_freebsd_use_tcp_nopush && !c->tcp_nopush) { |
134 if (ngx_freebsd_sendfile_nbytes_bug == 0) { | 157 if (ngx_freebsd_sendfile_nbytes_bug == 0) { |
135 hsize = 0; | 158 hsize = 0; |
136 } | 159 } |
137 | 160 |
138 rc = sendfile(file->file->fd, c->fd, file->file_pos, | 161 rc = sendfile(file->file->fd, c->fd, file->file_pos, |
139 (size_t) (file->file_last - file->file_pos) + hsize, | 162 fsize + hsize, &hdtr, &sent, 0); |
140 &hdtr, &sent, 0); | |
141 | 163 |
142 if (rc == -1) { | 164 if (rc == -1) { |
143 err = ngx_errno; | 165 err = ngx_errno; |
144 | 166 |
145 if (err == NGX_EINTR) { | 167 if (err == NGX_EINTR) { |
146 eintr = 1; | 168 eintr = 1; |
169 } | |
170 | |
171 if (err == NGX_EAGAIN) { | |
172 eagain = 1; | |
147 } | 173 } |
148 | 174 |
149 if (err == NGX_EAGAIN || err == NGX_EINTR) { | 175 if (err == NGX_EAGAIN || err == NGX_EINTR) { |
150 ngx_log_error(NGX_LOG_INFO, c->log, err, | 176 ngx_log_error(NGX_LOG_INFO, c->log, err, |
151 "sendfile() sent only %qd bytes", sent); | 177 "sendfile() sent only %qd bytes", sent); |
157 } | 183 } |
158 } | 184 } |
159 | 185 |
160 #if (NGX_DEBUG_WRITE_CHAIN) | 186 #if (NGX_DEBUG_WRITE_CHAIN) |
161 ngx_log_debug(c->log, "sendfile: %d, @%qd %qd:%d" _ | 187 ngx_log_debug(c->log, "sendfile: %d, @%qd %qd:%d" _ |
162 rc _ file->file_pos _ sent _ | 188 rc _ file->file_pos _ sent _ fsize + hsize); |
163 (size_t) (file->file_last - file->file_pos) + hsize); | |
164 #endif | 189 #endif |
165 | 190 |
166 } else { | 191 } else { |
167 rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); | 192 rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); |
168 | 193 |
169 if (rc == -1) { | 194 if (rc == -1) { |
170 err = ngx_errno; | 195 err = ngx_errno; |
171 if (err == NGX_EAGAIN) { | 196 if (err == NGX_EAGAIN) { |
197 eagain = 1; | |
172 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); | 198 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); |
173 | 199 |
174 } else if (err == NGX_EINTR) { | 200 } else if (err == NGX_EINTR) { |
175 eintr = 1; | 201 eintr = 1; |
176 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR"); | 202 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR"); |
188 #endif | 214 #endif |
189 } | 215 } |
190 | 216 |
191 c->sent += sent; | 217 c->sent += sent; |
192 | 218 |
193 for (ce = in; ce && sent > 0; ce = ce->next) { | 219 for (ce = in; ce; ce = ce->next) { |
194 | 220 |
195 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { | 221 if (ngx_hunk_special(ce->hunk)) { |
196 size = ce->hunk->last - ce->hunk->pos; | 222 continue; |
197 } else { | 223 } |
198 size = ce->hunk->file_last - ce->hunk->file_pos; | 224 |
199 } | 225 if (sent == 0) { |
226 break; | |
227 } | |
228 | |
229 size = ngx_hunk_size(ce->hunk); | |
200 | 230 |
201 if (sent >= size) { | 231 if (sent >= size) { |
202 sent -= size; | 232 sent -= size; |
203 | 233 |
204 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { | 234 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { |
221 } | 251 } |
222 | 252 |
223 break; | 253 break; |
224 } | 254 } |
225 | 255 |
226 ngx_destroy_array(&trailer); | |
227 ngx_destroy_array(&header); | |
228 | |
229 in = ce; | 256 in = ce; |
230 | 257 |
231 } while ((tail && tail == ce) || eintr); | 258 if (eagain) { |
232 | 259 c->write->ready = 0; |
233 if (ce) { | 260 break; |
261 } | |
262 | |
263 /* "tail == in" means that a single sendfile() is complete */ | |
264 | |
265 } while ((tail && tail == in) || eintr); | |
266 | |
267 if (in) { | |
234 c->write->ready = 0; | 268 c->write->ready = 0; |
235 } | 269 } |
236 | 270 |
237 return ce; | 271 return in; |
238 } | 272 } |