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 }