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 }