Mercurial > hg > nginx-vendor-1-0
comparison src/os/unix/ngx_linux_sendfile_chain.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | 4b2dafa26fe2 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 | |
11 | |
12 /* | |
13 * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit | |
14 * offsets only and the including <sys/sendfile.h> breaks the compiling | |
15 * if off_t is 64 bit wide. So we use own sendfile() definition where offset | |
16 * parameter is int32_t and use sendfile() with the file parts below 2G. | |
17 * | |
18 * Linux 2.4.21 has a new sendfile64() syscall #239. | |
19 */ | |
20 | |
21 | |
22 #define NGX_HEADERS 8 | |
23 | |
24 | |
25 ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, | |
26 off_t limit) | |
27 { | |
28 int rc; | |
29 u_char *prev; | |
30 off_t fprev, send, sprev, aligned; | |
31 size_t fsize; | |
32 ssize_t size, sent; | |
33 ngx_uint_t eintr, complete; | |
34 ngx_err_t err; | |
35 ngx_buf_t *file; | |
36 ngx_array_t header; | |
37 ngx_event_t *wev; | |
38 ngx_chain_t *cl; | |
39 struct iovec *iov, headers[NGX_HEADERS]; | |
40 #if (HAVE_SENDFILE64) | |
41 off_t offset; | |
42 #else | |
43 int32_t offset; | |
44 #endif | |
45 | |
46 wev = c->write; | |
47 | |
48 if (!wev->ready) { | |
49 return in; | |
50 } | |
51 | |
52 send = 0; | |
53 | |
54 header.elts = headers; | |
55 header.size = sizeof(struct iovec); | |
56 header.nalloc = NGX_HEADERS; | |
57 header.pool = c->pool; | |
58 | |
59 for ( ;; ) { | |
60 file = NULL; | |
61 fsize = 0; | |
62 eintr = 0; | |
63 complete = 0; | |
64 sprev = send; | |
65 | |
66 header.nelts = 0; | |
67 | |
68 prev = NULL; | |
69 iov = NULL; | |
70 | |
71 /* create the iovec and coalesce the neighbouring bufs */ | |
72 | |
73 for (cl = in; | |
74 cl && header.nelts < IOV_MAX && send < limit; | |
75 cl = cl->next) | |
76 { | |
77 if (ngx_buf_special(cl->buf)) { | |
78 continue; | |
79 } | |
80 | |
81 if (!ngx_buf_in_memory_only(cl->buf)) { | |
82 break; | |
83 } | |
84 | |
85 size = cl->buf->last - cl->buf->pos; | |
86 | |
87 if (send + size > limit) { | |
88 size = limit - send; | |
89 } | |
90 | |
91 if (prev == cl->buf->pos) { | |
92 iov->iov_len += size; | |
93 | |
94 } else { | |
95 if (!(iov = ngx_array_push(&header))) { | |
96 return NGX_CHAIN_ERROR; | |
97 } | |
98 | |
99 iov->iov_base = (void *) cl->buf->pos; | |
100 iov->iov_len = size; | |
101 } | |
102 | |
103 prev = cl->buf->pos + size; | |
104 send += size; | |
105 } | |
106 | |
107 /* set TCP_CORK if there is a header before a file */ | |
108 | |
109 if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET | |
110 && header.nelts != 0 | |
111 && cl | |
112 && cl->buf->in_file) | |
113 { | |
114 if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { | |
115 err = ngx_errno; | |
116 | |
117 /* | |
118 * there is a tiny chance to be interrupted, however | |
119 * we continue a processing without the TCP_CORK | |
120 */ | |
121 | |
122 if (err != NGX_EINTR) { | |
123 wev->error = 1; | |
124 ngx_connection_error(c, err, ngx_tcp_nopush_n " failed"); | |
125 return NGX_CHAIN_ERROR; | |
126 } | |
127 | |
128 } else { | |
129 c->tcp_nopush = NGX_TCP_NOPUSH_SET; | |
130 | |
131 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
132 "tcp_nopush"); | |
133 } | |
134 } | |
135 | |
136 /* get the file buf */ | |
137 | |
138 if (header.nelts == 0 && cl && cl->buf->in_file && send < limit) { | |
139 file = cl->buf; | |
140 | |
141 /* coalesce the neighbouring file bufs */ | |
142 | |
143 do { | |
144 size = (size_t) (cl->buf->file_last - cl->buf->file_pos); | |
145 | |
146 if (send + size > limit) { | |
147 size = limit - send; | |
148 | |
149 aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) | |
150 & ~(ngx_pagesize - 1); | |
151 | |
152 if (aligned <= cl->buf->file_last) { | |
153 size = aligned - cl->buf->file_pos; | |
154 } | |
155 } | |
156 | |
157 fsize += size; | |
158 send += size; | |
159 fprev = cl->buf->file_pos + size; | |
160 cl = cl->next; | |
161 | |
162 } while (cl | |
163 && cl->buf->in_file | |
164 && send < limit | |
165 && file->file->fd == cl->buf->file->fd | |
166 && fprev == cl->buf->file_pos); | |
167 } | |
168 | |
169 if (file) { | |
170 #if (HAVE_SENDFILE64) | |
171 offset = file->file_pos; | |
172 #else | |
173 offset = (int32_t) file->file_pos; | |
174 #endif | |
175 rc = sendfile(c->fd, file->file->fd, &offset, fsize); | |
176 | |
177 if (rc == -1) { | |
178 err = ngx_errno; | |
179 | |
180 if (err == NGX_EAGAIN || err == NGX_EINTR) { | |
181 if (err == NGX_EINTR) { | |
182 eintr = 1; | |
183 } | |
184 | |
185 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | |
186 "sendfile() is not ready"); | |
187 | |
188 } else { | |
189 wev->error = 1; | |
190 ngx_connection_error(c, err, "sendfile() failed"); | |
191 return NGX_CHAIN_ERROR; | |
192 } | |
193 } | |
194 | |
195 sent = rc > 0 ? rc : 0; | |
196 | |
197 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
198 "sendfile: %d, @" OFF_T_FMT " %d:%d", | |
199 rc, file->file_pos, sent, fsize); | |
200 | |
201 } else { | |
202 rc = writev(c->fd, header.elts, header.nelts); | |
203 | |
204 if (rc == -1) { | |
205 err = ngx_errno; | |
206 | |
207 if (err == NGX_EAGAIN || err == NGX_EINTR) { | |
208 if (err == NGX_EINTR) { | |
209 eintr = 1; | |
210 } | |
211 | |
212 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | |
213 "writev() not ready"); | |
214 | |
215 } else { | |
216 wev->error = 1; | |
217 ngx_connection_error(c, err, "writev() failed"); | |
218 return NGX_CHAIN_ERROR; | |
219 } | |
220 } | |
221 | |
222 sent = rc > 0 ? rc : 0; | |
223 | |
224 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %d", sent); | |
225 } | |
226 | |
227 if (send - sprev == sent) { | |
228 complete = 1; | |
229 } | |
230 | |
231 c->sent += sent; | |
232 | |
233 for (cl = in; cl; cl = cl->next) { | |
234 | |
235 if (ngx_buf_special(cl->buf)) { | |
236 continue; | |
237 } | |
238 | |
239 if (sent == 0) { | |
240 break; | |
241 } | |
242 | |
243 size = ngx_buf_size(cl->buf); | |
244 | |
245 if (sent >= size) { | |
246 sent -= size; | |
247 | |
248 if (ngx_buf_in_memory(cl->buf)) { | |
249 cl->buf->pos = cl->buf->last; | |
250 } | |
251 | |
252 if (cl->buf->in_file) { | |
253 cl->buf->file_pos = cl->buf->file_last; | |
254 } | |
255 | |
256 continue; | |
257 } | |
258 | |
259 if (ngx_buf_in_memory(cl->buf)) { | |
260 cl->buf->pos += sent; | |
261 } | |
262 | |
263 if (cl->buf->in_file) { | |
264 cl->buf->file_pos += sent; | |
265 } | |
266 | |
267 break; | |
268 } | |
269 | |
270 if (eintr) { | |
271 continue; | |
272 } | |
273 | |
274 if (!complete) { | |
275 wev->ready = 0; | |
276 return cl; | |
277 } | |
278 | |
279 if (send >= limit || cl == NULL) { | |
280 return cl; | |
281 } | |
282 | |
283 in = cl; | |
284 } | |
285 } |