Annotation of embedaddon/nginx/src/os/unix/ngx_linux_sendfile_chain.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (C) Igor Sysoev
4: * Copyright (C) Nginx, Inc.
5: */
6:
7:
8: #include <ngx_config.h>
9: #include <ngx_core.h>
10: #include <ngx_event.h>
11:
12:
13: /*
14: * 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,
16: * if off_t is 64 bit wide. So we use own sendfile() definition, where offset
17: * parameter is int32_t, and use sendfile() for the file parts below 2G only,
18: * see src/os/unix/ngx_linux_config.h
19: *
20: * Linux 2.4.21 has the new sendfile64() syscall #239.
21: *
22: * On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter
23: * more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL,
24: * so we limit it to 2G-1 bytes.
25: */
26:
27: #define NGX_SENDFILE_LIMIT 2147483647L
28:
29:
30: #if (IOV_MAX > 64)
31: #define NGX_HEADERS 64
32: #else
33: #define NGX_HEADERS IOV_MAX
34: #endif
35:
36:
37: ngx_chain_t *
38: ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
39: {
40: int rc, tcp_nodelay;
41: off_t size, send, prev_send, aligned, sent, fprev;
42: u_char *prev;
43: size_t file_size;
44: ngx_err_t err;
45: ngx_buf_t *file;
46: ngx_uint_t eintr, complete;
47: ngx_array_t header;
48: ngx_event_t *wev;
49: ngx_chain_t *cl;
50: struct iovec *iov, headers[NGX_HEADERS];
51: #if (NGX_HAVE_SENDFILE64)
52: off_t offset;
53: #else
54: int32_t offset;
55: #endif
56:
57: wev = c->write;
58:
59: if (!wev->ready) {
60: return in;
61: }
62:
63:
64: /* the maximum limit size is 2G-1 - the page size */
65:
66: if (limit == 0 || limit > (off_t) (NGX_SENDFILE_LIMIT - ngx_pagesize)) {
67: limit = NGX_SENDFILE_LIMIT - ngx_pagesize;
68: }
69:
70:
71: send = 0;
72:
73: header.elts = headers;
74: header.size = sizeof(struct iovec);
75: header.nalloc = NGX_HEADERS;
76: header.pool = c->pool;
77:
78: for ( ;; ) {
79: file = NULL;
80: file_size = 0;
81: eintr = 0;
82: complete = 0;
83: prev_send = send;
84:
85: header.nelts = 0;
86:
87: prev = NULL;
88: iov = NULL;
89:
90: /* create the iovec and coalesce the neighbouring bufs */
91:
92: for (cl = in; cl && send < limit; cl = cl->next) {
93:
94: if (ngx_buf_special(cl->buf)) {
95: continue;
96: }
97:
98: #if 1
99: if (!ngx_buf_in_memory(cl->buf) && !cl->buf->in_file) {
100: ngx_log_error(NGX_LOG_ALERT, c->log, 0,
101: "zero size buf in sendfile "
102: "t:%d r:%d f:%d %p %p-%p %p %O-%O",
103: cl->buf->temporary,
104: cl->buf->recycled,
105: cl->buf->in_file,
106: cl->buf->start,
107: cl->buf->pos,
108: cl->buf->last,
109: cl->buf->file,
110: cl->buf->file_pos,
111: cl->buf->file_last);
112:
113: ngx_debug_point();
114:
115: return NGX_CHAIN_ERROR;
116: }
117: #endif
118:
119: if (!ngx_buf_in_memory_only(cl->buf)) {
120: break;
121: }
122:
123: size = cl->buf->last - cl->buf->pos;
124:
125: if (send + size > limit) {
126: size = limit - send;
127: }
128:
129: if (prev == cl->buf->pos) {
130: iov->iov_len += (size_t) size;
131:
132: } else {
133: if (header.nelts >= IOV_MAX) {
134: break;
135: }
136:
137: iov = ngx_array_push(&header);
138: if (iov == NULL) {
139: return NGX_CHAIN_ERROR;
140: }
141:
142: iov->iov_base = (void *) cl->buf->pos;
143: iov->iov_len = (size_t) size;
144: }
145:
146: prev = cl->buf->pos + (size_t) size;
147: send += size;
148: }
149:
150: /* set TCP_CORK if there is a header before a file */
151:
152: if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET
153: && header.nelts != 0
154: && cl
155: && cl->buf->in_file)
156: {
157: /* the TCP_CORK and TCP_NODELAY are mutually exclusive */
158:
159: if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) {
160:
161: tcp_nodelay = 0;
162:
163: if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
164: (const void *) &tcp_nodelay, sizeof(int)) == -1)
165: {
166: err = ngx_errno;
167:
168: /*
169: * there is a tiny chance to be interrupted, however,
170: * we continue a processing with the TCP_NODELAY
171: * and without the TCP_CORK
172: */
173:
174: if (err != NGX_EINTR) {
175: wev->error = 1;
176: ngx_connection_error(c, err,
177: "setsockopt(TCP_NODELAY) failed");
178: return NGX_CHAIN_ERROR;
179: }
180:
181: } else {
182: c->tcp_nodelay = NGX_TCP_NODELAY_UNSET;
183:
184: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
185: "no tcp_nodelay");
186: }
187: }
188:
189: if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
190:
191: if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
192: err = ngx_errno;
193:
194: /*
195: * there is a tiny chance to be interrupted, however,
196: * we continue a processing without the TCP_CORK
197: */
198:
199: if (err != NGX_EINTR) {
200: wev->error = 1;
201: ngx_connection_error(c, err,
202: ngx_tcp_nopush_n " failed");
203: return NGX_CHAIN_ERROR;
204: }
205:
206: } else {
207: c->tcp_nopush = NGX_TCP_NOPUSH_SET;
208:
209: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
210: "tcp_nopush");
211: }
212: }
213: }
214:
215: /* get the file buf */
216:
217: if (header.nelts == 0 && cl && cl->buf->in_file && send < limit) {
218: file = cl->buf;
219:
220: /* coalesce the neighbouring file bufs */
221:
222: do {
223: size = cl->buf->file_last - cl->buf->file_pos;
224:
225: if (send + size > limit) {
226: size = limit - send;
227:
228: aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
229: & ~((off_t) ngx_pagesize - 1);
230:
231: if (aligned <= cl->buf->file_last) {
232: size = aligned - cl->buf->file_pos;
233: }
234: }
235:
236: file_size += (size_t) size;
237: send += size;
238: fprev = cl->buf->file_pos + size;
239: cl = cl->next;
240:
241: } while (cl
242: && cl->buf->in_file
243: && send < limit
244: && file->file->fd == cl->buf->file->fd
245: && fprev == cl->buf->file_pos);
246: }
247:
248: if (file) {
249: #if 1
250: if (file_size == 0) {
251: ngx_debug_point();
252: return NGX_CHAIN_ERROR;
253: }
254: #endif
255: #if (NGX_HAVE_SENDFILE64)
256: offset = file->file_pos;
257: #else
258: offset = (int32_t) file->file_pos;
259: #endif
260:
261: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
262: "sendfile: @%O %uz", file->file_pos, file_size);
263:
264: rc = sendfile(c->fd, file->file->fd, &offset, file_size);
265:
266: if (rc == -1) {
267: err = ngx_errno;
268:
269: switch (err) {
270: case NGX_EAGAIN:
271: break;
272:
273: case NGX_EINTR:
274: eintr = 1;
275: break;
276:
277: default:
278: wev->error = 1;
279: ngx_connection_error(c, err, "sendfile() failed");
280: return NGX_CHAIN_ERROR;
281: }
282:
283: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
284: "sendfile() is not ready");
285: }
286:
287: sent = rc > 0 ? rc : 0;
288:
289: ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
290: "sendfile: %d, @%O %O:%uz",
291: rc, file->file_pos, sent, file_size);
292:
293: } else {
294: rc = writev(c->fd, header.elts, header.nelts);
295:
296: if (rc == -1) {
297: err = ngx_errno;
298:
299: switch (err) {
300: case NGX_EAGAIN:
301: break;
302:
303: case NGX_EINTR:
304: eintr = 1;
305: break;
306:
307: default:
308: wev->error = 1;
309: ngx_connection_error(c, err, "writev() failed");
310: return NGX_CHAIN_ERROR;
311: }
312:
313: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
314: "writev() not ready");
315: }
316:
317: sent = rc > 0 ? rc : 0;
318:
319: ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %O", sent);
320: }
321:
322: if (send - prev_send == sent) {
323: complete = 1;
324: }
325:
326: c->sent += sent;
327:
328: for (cl = in; cl; cl = cl->next) {
329:
330: if (ngx_buf_special(cl->buf)) {
331: continue;
332: }
333:
334: if (sent == 0) {
335: break;
336: }
337:
338: size = ngx_buf_size(cl->buf);
339:
340: if (sent >= size) {
341: sent -= size;
342:
343: if (ngx_buf_in_memory(cl->buf)) {
344: cl->buf->pos = cl->buf->last;
345: }
346:
347: if (cl->buf->in_file) {
348: cl->buf->file_pos = cl->buf->file_last;
349: }
350:
351: continue;
352: }
353:
354: if (ngx_buf_in_memory(cl->buf)) {
355: cl->buf->pos += (size_t) sent;
356: }
357:
358: if (cl->buf->in_file) {
359: cl->buf->file_pos += sent;
360: }
361:
362: break;
363: }
364:
365: if (eintr) {
366: continue;
367: }
368:
369: if (!complete) {
370: wev->ready = 0;
371: return cl;
372: }
373:
374: if (send >= limit || cl == NULL) {
375: return cl;
376: }
377:
378: in = cl;
379: }
380: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>