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 }