Mercurial > hg > nginx
comparison src/os/unix/ngx_linux_sendfile_chain.c @ 5997:c901f2764c27
Refactored ngx_linux_sendfile_chain() even more.
The code that calls sendfile() was cut into a separate function.
This simplifies EINTR processing, yet is needed for the following
changes that add threads support.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Fri, 27 Feb 2015 19:19:08 +0300 |
parents | c50b5ed3cd4b |
children | b550563ef96e |
comparison
equal
deleted
inserted
replaced
5996:ab660d7c9980 | 5997:c901f2764c27 |
---|---|
6 | 6 |
7 | 7 |
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_event.h> | 10 #include <ngx_event.h> |
11 | |
12 | |
13 static ssize_t ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file, | |
14 size_t size); | |
11 | 15 |
12 | 16 |
13 /* | 17 /* |
14 * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit | 18 * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit |
15 * offsets only, and the including <sys/sendfile.h> breaks the compiling, | 19 * offsets only, and the including <sys/sendfile.h> breaks the compiling, |
34 off_t send, prev_send, sent; | 38 off_t send, prev_send, sent; |
35 size_t file_size; | 39 size_t file_size; |
36 ssize_t n; | 40 ssize_t n; |
37 ngx_err_t err; | 41 ngx_err_t err; |
38 ngx_buf_t *file; | 42 ngx_buf_t *file; |
39 ngx_uint_t eintr; | |
40 ngx_event_t *wev; | 43 ngx_event_t *wev; |
41 ngx_chain_t *cl; | 44 ngx_chain_t *cl; |
42 ngx_iovec_t header; | 45 ngx_iovec_t header; |
43 struct iovec headers[NGX_IOVS_PREALLOCATE]; | 46 struct iovec headers[NGX_IOVS_PREALLOCATE]; |
44 #if (NGX_HAVE_SENDFILE64) | |
45 off_t offset; | |
46 #else | |
47 int32_t offset; | |
48 #endif | |
49 | 47 |
50 wev = c->write; | 48 wev = c->write; |
51 | 49 |
52 if (!wev->ready) { | 50 if (!wev->ready) { |
53 return in; | 51 return in; |
65 | 63 |
66 header.iovs = headers; | 64 header.iovs = headers; |
67 header.nalloc = NGX_IOVS_PREALLOCATE; | 65 header.nalloc = NGX_IOVS_PREALLOCATE; |
68 | 66 |
69 for ( ;; ) { | 67 for ( ;; ) { |
70 eintr = 0; | |
71 prev_send = send; | 68 prev_send = send; |
72 | 69 |
73 /* create the iovec and coalesce the neighbouring bufs */ | 70 /* create the iovec and coalesce the neighbouring bufs */ |
74 | 71 |
75 cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); | 72 cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); |
159 if (file_size == 0) { | 156 if (file_size == 0) { |
160 ngx_debug_point(); | 157 ngx_debug_point(); |
161 return NGX_CHAIN_ERROR; | 158 return NGX_CHAIN_ERROR; |
162 } | 159 } |
163 #endif | 160 #endif |
164 #if (NGX_HAVE_SENDFILE64) | 161 n = ngx_linux_sendfile(c, file, file_size); |
165 offset = file->file_pos; | 162 |
166 #else | 163 if (n == NGX_ERROR) { |
167 offset = (int32_t) file->file_pos; | 164 return NGX_CHAIN_ERROR; |
168 #endif | 165 } |
169 | 166 |
170 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 167 sent = (n == NGX_AGAIN) ? 0 : n; |
171 "sendfile: @%O %uz", file->file_pos, file_size); | |
172 | |
173 n = sendfile(c->fd, file->file->fd, &offset, file_size); | |
174 | |
175 if (n == -1) { | |
176 err = ngx_errno; | |
177 | |
178 switch (err) { | |
179 case NGX_EAGAIN: | |
180 break; | |
181 | |
182 case NGX_EINTR: | |
183 eintr = 1; | |
184 break; | |
185 | |
186 default: | |
187 wev->error = 1; | |
188 ngx_connection_error(c, err, "sendfile() failed"); | |
189 return NGX_CHAIN_ERROR; | |
190 } | |
191 | |
192 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | |
193 "sendfile() is not ready"); | |
194 } | |
195 | |
196 sent = n > 0 ? n : 0; | |
197 | |
198 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
199 "sendfile: %z, @%O %O:%uz", | |
200 n, file->file_pos, sent, file_size); | |
201 | 168 |
202 } else { | 169 } else { |
203 n = ngx_writev(c, &header); | 170 n = ngx_writev(c, &header); |
204 | 171 |
205 if (n == NGX_ERROR) { | 172 if (n == NGX_ERROR) { |
210 } | 177 } |
211 | 178 |
212 c->sent += sent; | 179 c->sent += sent; |
213 | 180 |
214 in = ngx_chain_update_sent(in, sent); | 181 in = ngx_chain_update_sent(in, sent); |
215 | |
216 if (eintr) { | |
217 send = prev_send; | |
218 continue; | |
219 } | |
220 | 182 |
221 if (send - prev_send != sent) { | 183 if (send - prev_send != sent) { |
222 wev->ready = 0; | 184 wev->ready = 0; |
223 return in; | 185 return in; |
224 } | 186 } |
226 if (send >= limit || in == NULL) { | 188 if (send >= limit || in == NULL) { |
227 return in; | 189 return in; |
228 } | 190 } |
229 } | 191 } |
230 } | 192 } |
193 | |
194 | |
195 static ssize_t | |
196 ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) | |
197 { | |
198 #if (NGX_HAVE_SENDFILE64) | |
199 off_t offset; | |
200 #else | |
201 int32_t offset; | |
202 #endif | |
203 ssize_t n; | |
204 ngx_err_t err; | |
205 | |
206 #if (NGX_HAVE_SENDFILE64) | |
207 offset = file->file_pos; | |
208 #else | |
209 offset = (int32_t) file->file_pos; | |
210 #endif | |
211 | |
212 eintr: | |
213 | |
214 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
215 "sendfile: @%O %uz", file->file_pos, size); | |
216 | |
217 n = sendfile(c->fd, file->file->fd, &offset, size); | |
218 | |
219 if (n == -1) { | |
220 err = ngx_errno; | |
221 | |
222 switch (err) { | |
223 case NGX_EAGAIN: | |
224 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | |
225 "sendfile() is not ready"); | |
226 return NGX_AGAIN; | |
227 | |
228 case NGX_EINTR: | |
229 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | |
230 "sendfile() was interrupted"); | |
231 goto eintr; | |
232 | |
233 default: | |
234 c->write->error = 1; | |
235 ngx_connection_error(c, err, "sendfile() failed"); | |
236 return NGX_ERROR; | |
237 } | |
238 } | |
239 | |
240 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %z of %uz @%O", | |
241 n, size, file->file_pos); | |
242 | |
243 return n; | |
244 } |