Mercurial > hg > nginx
comparison src/os/unix/ngx_freebsd_sendfile_chain.c @ 253:b6793bc5034b
nginx-0.0.2-2004-02-09-10:46:43 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 09 Feb 2004 07:46:43 +0000 |
parents | 05592fd7a436 |
children | 8c5bdde0d9f0 |
comparison
equal
deleted
inserted
replaced
252:84b1c672ec5a | 253:b6793bc5034b |
---|---|
3 #include <ngx_core.h> | 3 #include <ngx_core.h> |
4 #include <ngx_event.h> | 4 #include <ngx_event.h> |
5 | 5 |
6 | 6 |
7 /* | 7 /* |
8 * FreeBSD's sendfile() often sends 4K pages over ethernet in 3 packets: 2x1460 | 8 * Although FreeBSD sendfile() allows to pass a header and a trailer |
9 * and 1176 or in 6 packets: 5x1460 and 892. Besides although sendfile() | 9 * it never sends a header with a part of the file in one packet until |
10 * allows to pass the header and the trailer it never sends the header or | 10 * FreeBSD 5.2-STABLE. Besides over the fast ethernet connection sendfile() |
11 * the trailer with the part of the file in one packet. So we use TCP_NOPUSH | 11 * can send the partially filled packets, i.e. the 8 file pages can be sent |
12 * (similar to Linux's TCP_CORK) to postpone the sending - it not only sends | 12 * as 11 full 1460-bytes packets, then one incomplete 324-bytes packet, and |
13 * the header and the first part of the file in one packet but also sends | 13 * then again 11 full 1460-bytes packets. |
14 * 4K pages in the full packets. | |
15 * | 14 * |
16 * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending | 15 * So we use the TCP_NOPUSH option (similar to Linux's TCP_CORK) |
16 * to postpone the sending - it not only sends a header and the first part | |
17 * of the file in one packet but also sends file pages in the full packets. | |
18 * | |
19 * But until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending | |
17 * data that less than MSS so that data can be sent with 5 second delay. | 20 * data that less than MSS so that data can be sent with 5 second delay. |
18 * We do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used | 21 * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used |
19 * for non-keepalive HTTP connections. | 22 * for non-keepalive HTTP connections. |
20 */ | 23 */ |
21 | 24 |
22 | 25 |
23 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) | 26 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) |
24 { | 27 { |
25 int rc; | 28 int rc; |
26 char *prev; | 29 char *prev; |
27 off_t sent, fprev; | 30 off_t sent, fprev; |
28 size_t hsize, fsize, size; | 31 size_t hsize, fsize, size; |
29 ngx_int_t eintr, eagain, level; | 32 ngx_int_t eintr, eagain; |
30 struct iovec *iov; | 33 struct iovec *iov; |
31 struct sf_hdtr hdtr; | 34 struct sf_hdtr hdtr; |
32 ngx_err_t err; | 35 ngx_err_t err; |
33 ngx_hunk_t *file; | 36 ngx_hunk_t *file; |
34 ngx_array_t header, trailer; | 37 ngx_array_t header, trailer; |
43 | 46 |
44 #if (HAVE_KQUEUE) | 47 #if (HAVE_KQUEUE) |
45 | 48 |
46 if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) && wev->kq_eof) { | 49 if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) && wev->kq_eof) { |
47 ngx_log_error(NGX_LOG_INFO, c->log, wev->kq_errno, | 50 ngx_log_error(NGX_LOG_INFO, c->log, wev->kq_errno, |
48 "kevent() reported about closed connection"); | 51 "kevent() reported about an closed connection"); |
49 | 52 |
50 wev->error = 1; | 53 wev->error = 1; |
51 return NGX_CHAIN_ERROR; | 54 return NGX_CHAIN_ERROR; |
52 } | 55 } |
53 | 56 |
57 file = NULL; | 60 file = NULL; |
58 fsize = 0; | 61 fsize = 0; |
59 hsize = 0; | 62 hsize = 0; |
60 eintr = 0; | 63 eintr = 0; |
61 eagain = 0; | 64 eagain = 0; |
62 level = NGX_LOG_CRIT; | |
63 | 65 |
64 ngx_init_array(header, c->pool, 10, sizeof(struct iovec), | 66 ngx_init_array(header, c->pool, 10, sizeof(struct iovec), |
65 NGX_CHAIN_ERROR); | 67 NGX_CHAIN_ERROR); |
66 ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), | 68 ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), |
67 NGX_CHAIN_ERROR); | 69 NGX_CHAIN_ERROR); |
150 tail = cl; | 152 tail = cl; |
151 | 153 |
152 if (file) { | 154 if (file) { |
153 | 155 |
154 if (ngx_freebsd_use_tcp_nopush && c->tcp_nopush == 0) { | 156 if (ngx_freebsd_use_tcp_nopush && c->tcp_nopush == 0) { |
155 c->tcp_nopush = 1; | |
156 | |
157 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "tcp_nopush"); | |
158 | 157 |
159 if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { | 158 if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { |
160 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno, | 159 err = ngx_errno; |
161 ngx_tcp_nopush_n " failed"); | 160 |
162 return NGX_CHAIN_ERROR; | 161 /* |
162 * there is a tiny chance to be interrupted, however | |
163 * we continue a processing without the TCP_NOPUSH | |
164 */ | |
165 | |
166 if (err != NGX_EINTR) { | |
167 wev->error = 1; | |
168 ngx_connection_error(c, err, | |
169 ngx_tcp_nopush_n " failed"); | |
170 return NGX_CHAIN_ERROR; | |
171 } | |
172 | |
173 } else { | |
174 c->tcp_nopush = 1; | |
175 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
176 "tcp_nopush"); | |
163 } | 177 } |
164 } | 178 } |
165 | 179 |
166 hdtr.headers = (struct iovec *) header.elts; | 180 hdtr.headers = (struct iovec *) header.elts; |
167 hdtr.hdr_cnt = header.nelts; | 181 hdtr.hdr_cnt = header.nelts; |
183 fsize + hsize, &hdtr, &sent, 0); | 197 fsize + hsize, &hdtr, &sent, 0); |
184 | 198 |
185 if (rc == -1) { | 199 if (rc == -1) { |
186 err = ngx_errno; | 200 err = ngx_errno; |
187 | 201 |
188 if (err == NGX_EINTR) { | |
189 eintr = 1; | |
190 | |
191 } else if (err == NGX_EAGAIN) { | |
192 eagain = 1; | |
193 | |
194 } else if (err == NGX_EPIPE || err == NGX_ENOTCONN) { | |
195 level = NGX_LOG_INFO; | |
196 } | |
197 | |
198 if (err == NGX_EAGAIN || err == NGX_EINTR) { | 202 if (err == NGX_EAGAIN || err == NGX_EINTR) { |
203 if (err == NGX_EINTR) { | |
204 eintr = 1; | |
205 | |
206 } else { | |
207 eagain = 1; | |
208 } | |
209 | |
199 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, | 210 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, |
200 "sendfile() sent only " OFF_T_FMT " bytes", | 211 "sendfile() sent only " OFF_T_FMT " bytes", |
201 sent); | 212 sent); |
202 | 213 |
203 } else { | 214 } else { |
204 wev->error = 1; | 215 wev->error = 1; |
205 #if 0 | 216 ngx_connection_error(c, err, "sendfile() failed"); |
206 ngx_log_error(level, c->log, err, | |
207 "sendfile() failed"); | |
208 #else | |
209 ngx_log_error(level, c->log, err, | |
210 "sendfile(#%d) failed", c->fd); | |
211 #endif | |
212 return NGX_CHAIN_ERROR; | 217 return NGX_CHAIN_ERROR; |
213 } | 218 } |
214 } | 219 } |
215 | 220 |
216 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | 221 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, |
221 rc = writev(c->fd, header.elts, header.nelts); | 226 rc = writev(c->fd, header.elts, header.nelts); |
222 | 227 |
223 if (rc == -1) { | 228 if (rc == -1) { |
224 err = ngx_errno; | 229 err = ngx_errno; |
225 | 230 |
226 if (err == NGX_EINTR) { | |
227 eintr = 1; | |
228 | |
229 } else if (err == NGX_EPIPE) { | |
230 level = NGX_LOG_INFO; | |
231 } | |
232 | |
233 if (err == NGX_EAGAIN || err == NGX_EINTR) { | 231 if (err == NGX_EAGAIN || err == NGX_EINTR) { |
232 if (err == NGX_EINTR) { | |
233 eintr = 1; | |
234 } | |
235 | |
234 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | 236 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, |
235 "writev() not ready"); | 237 "writev() not ready"); |
236 | 238 |
237 } else { | 239 } else { |
238 wev->error = 1; | 240 wev->error = 1; |
239 ngx_log_error(level, c->log, err, "writev() failed"); | 241 ngx_connection_error(c, err, "writev() failed"); |
240 return NGX_CHAIN_ERROR; | 242 return NGX_CHAIN_ERROR; |
241 } | 243 } |
242 } | 244 } |
243 | 245 |
244 sent = rc > 0 ? rc : 0; | 246 sent = rc > 0 ? rc : 0; |
290 | 292 |
291 if (eagain) { | 293 if (eagain) { |
292 | 294 |
293 /* | 295 /* |
294 * sendfile() can return EAGAIN even if it has sent | 296 * sendfile() can return EAGAIN even if it has sent |
295 * a whole file part and successive sendfile() would | 297 * a whole file part but the successive sendfile() call would |
296 * return EAGAIN right away and would not send anything | 298 * return EAGAIN right away and would not send anything. |
299 * We use it as a hint. | |
297 */ | 300 */ |
298 | 301 |
299 wev->ready = 0; | 302 wev->ready = 0; |
300 break; | 303 break; |
301 } | 304 } |