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 }