Mercurial > hg > nginx
comparison src/os/unix/ngx_linux_sendfile_chain.c @ 195:8dee38ea9117
nginx-0.0.1-2003-11-25-23:44:56 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 25 Nov 2003 20:44:56 +0000 |
parents | 70d2345a903f |
children | 11fbd0fc041d |
comparison
equal
deleted
inserted
replaced
194:2357fa41738a | 195:8dee38ea9117 |
---|---|
1 | 1 |
2 #include <ngx_config.h> | 2 #include <ngx_config.h> |
3 #include <ngx_core.h> | 3 #include <ngx_core.h> |
4 #include <ngx_linux_init.h> | 4 #include <ngx_event.h> |
5 | 5 |
6 | 6 |
7 ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) | 7 ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) |
8 { | 8 { |
9 int rc, on, off; | 9 int rc; |
10 char *prev; | 10 char *prev; |
11 size_t hsize, size; | 11 off_t fprev; |
12 ssize_t sent; | 12 size_t size, fsize, sent; |
13 ngx_int_t use_cork, eintr; | |
13 struct iovec *iov; | 14 struct iovec *iov; |
14 struct sf_hdtr hdtr; | |
15 ngx_err_t err; | 15 ngx_err_t err; |
16 ngx_array_t header, trailer; | |
17 ngx_hunk_t *file; | 16 ngx_hunk_t *file; |
18 ngx_chain_t *ce; | 17 ngx_array_t header; |
19 | 18 ngx_event_t *wev; |
20 ce = in; | 19 ngx_chain_t *cl; |
21 file = NULL; | 20 |
22 hsize = 0; | 21 wev = c->write; |
23 | 22 |
24 on = 1; | 23 if (!wev->ready) { |
25 off = 0; | 24 return in; |
26 | 25 } |
27 ngx_init_array(header, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); | 26 |
28 ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); | 27 cork = 0; |
29 | 28 |
30 /* create the header iovec */ | 29 do { |
31 if (ngx_hunk_in_memory_only(ce->hunk)) { | 30 file = NULL; |
31 fsize = 0; | |
32 eintr = 0; | |
33 | |
34 ngx_init_array(header, c->pool, 10, sizeof(struct iovec), | |
35 NGX_CHAIN_ERROR); | |
36 | |
32 prev = NULL; | 37 prev = NULL; |
33 iov = NULL; | 38 iov = NULL; |
34 | 39 |
35 /* create the iovec and coalesce the neighbouring chain entries */ | 40 /* create the iovec and coalesce the neighbouring hunks */ |
36 while (ce && ngx_hunk_in_memory_only(ce->hunk)) { | 41 |
37 | 42 for (cl = in; cl; cl = cl->next) { |
38 if (prev == ce->hunk->pos) { | 43 if (ngx_hunk_special(cl->hunk)) { |
39 iov->iov_len += ce->hunk->last - ce->hunk->pos; | 44 continue; |
40 prev = ce->hunk->last; | 45 } |
46 | |
47 if (!ngx_hunk_in_memory_only(cl->hunk)) { | |
48 break; | |
49 } | |
50 | |
51 if (prev == cl->hunk->pos) { | |
52 iov->iov_len += cl->hunk->last - cl->hunk->pos; | |
41 | 53 |
42 } else { | 54 } else { |
43 ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR); | 55 ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR); |
44 iov->iov_base = ce->hunk->pos; | 56 iov->iov_base = cl->hunk->pos; |
45 iov->iov_len = ce->hunk->last - ce->hunk->pos; | 57 iov->iov_len = cl->hunk->last - cl->hunk->pos; |
46 prev = ce->hunk->last; | 58 } |
47 } | 59 |
48 | 60 prev = cl->hunk->last; |
49 if (ngx_freebsd_sendfile_nbytes_bug) { | 61 } |
50 hsize += ce->hunk->last - ce->hunk->pos; | 62 |
51 } | 63 /* set TCP_CORK if there is a header before a file */ |
52 | 64 |
53 ce = ce->next; | 65 if (!c->tcp_nopush |
54 } | 66 && header.nelts != 0 |
67 && cl | |
68 && cl->hunk->type & NGX_HUNK_FILE) | |
69 { | |
70 c->tcp_nopush = 1; | |
71 | |
72 ngx_log_debug(c->log, "CORK"); | |
73 | |
74 if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { | |
75 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno, | |
76 ngx_tcp_nopush_n " failed"); | |
77 return NGX_CHAIN_ERROR; | |
78 } | |
79 } | |
80 | |
81 if (header.nelts == 0 && cl && cl->hunk->type & NGX_HUNK_FILE) { | |
82 | |
83 /* get the file hunk */ | |
84 | |
85 file = cl->hunk; | |
86 fsize = (size_t) (file->file_last - file->file_pos); | |
87 fprev = file->file_last; | |
88 cl = cl->next; | |
89 | |
90 /* coalesce the neighbouring file hunks */ | |
91 | |
92 while (cl && (cl->hunk->type & NGX_HUNK_FILE)) { | |
93 if (file->file->fd != cl->hunk->file->fd | |
94 || fprev != cl->hunk->file_pos) | |
95 { | |
96 break; | |
97 } | |
98 | |
99 fsize += (size_t) (cl->hunk->file_last - cl->hunk->file_pos); | |
100 fprev = cl->hunk->file_last; | |
101 cl = cl->next; | |
102 } | |
103 } | |
104 | |
105 /* | |
106 * the tail is the rest of the chain that exceeded | |
107 * a single sendfile() capability | |
108 */ | |
109 | |
110 tail = cl; | |
111 | |
112 if (fsize) { | |
113 rc = sendfile(c->fd, file->file->fd, file->file_pos, fsize); | |
114 | |
115 if (rc == -1) { | |
116 err = ngx_errno; | |
117 if (err == NGX_EAGAIN) { | |
118 ngx_log_error(NGX_LOG_INFO, c->log, err, | |
119 "sendfile() EAGAIN"); | |
120 | |
121 } else if (err == NGX_EINTR) { | |
122 eintr = 1; | |
123 ngx_log_error(NGX_LOG_INFO, c->log, err, | |
124 "sendfile() EINTR"); | |
125 | |
126 } else { | |
127 ngx_log_error(NGX_LOG_CRIT, c->log, err, | |
128 "sendfile() failed"); | |
129 return NGX_CHAIN_ERROR; | |
130 } | |
131 } | |
132 | |
133 sent = rc > 0 ? rc : 0; | |
134 | |
135 #if (NGX_DEBUG_WRITE_CHAIN) | |
136 ngx_log_debug(c->log, "sendfile: %d, @" OFF_T_FMT " %d:%d" _ | |
137 rc _ file->file_pos _ sent _ fsize); | |
138 #endif | |
139 } else { | |
140 rc = writev(c->fd, header.elts, header.nelts); | |
141 | |
142 if (rc == -1) { | |
143 err = ngx_errno; | |
144 if (err == NGX_EAGAIN) { | |
145 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); | |
146 | |
147 } else if (err == NGX_EINTR) { | |
148 eintr = 1; | |
149 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR"); | |
150 | |
151 } else { | |
152 ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed"); | |
153 return NGX_CHAIN_ERROR; | |
154 } | |
155 } | |
156 | |
157 sent = rc > 0 ? rc : 0; | |
158 | |
159 #if (NGX_DEBUG_WRITE_CHAIN) | |
160 ngx_log_debug(c->log, "writev: %d" _ sent); | |
161 #endif | |
162 } | |
163 | |
164 c->sent += sent; | |
165 | |
166 for (cl = in; cl; cl = cl->next) { | |
167 | |
168 if (ngx_hunk_special(cl->hunk)) { | |
169 continue; | |
170 } | |
171 | |
172 if (sent == 0) { | |
173 break; | |
174 } | |
175 | |
176 size = ngx_hunk_size(cl->hunk); | |
177 | |
178 if (sent >= size) { | |
179 sent -= size; | |
180 | |
181 if (cl->hunk->type & NGX_HUNK_IN_MEMORY) { | |
182 cl->hunk->pos = cl->hunk->last; | |
183 } | |
184 | |
185 if (cl->hunk->type & NGX_HUNK_FILE) { | |
186 cl->hunk->file_pos = cl->hunk->file_last; | |
187 } | |
188 | |
189 continue; | |
190 } | |
191 | |
192 if (cl->hunk->type & NGX_HUNK_IN_MEMORY) { | |
193 cl->hunk->pos += sent; | |
194 } | |
195 | |
196 if (cl->hunk->type & NGX_HUNK_FILE) { | |
197 cl->hunk->file_pos += sent; | |
198 } | |
199 | |
200 break; | |
201 } | |
202 | |
203 in = cl; | |
204 | |
205 /* "tail == in" means that a single sendfile() is complete */ | |
206 | |
207 } while ((tail && tail == in) || eintr); | |
208 | |
209 if (in) { | |
210 wev->ready = 0; | |
55 } | 211 } |
56 | 212 |
57 /* TODO: coalesce the neighbouring file hunks */ | 213 return in; |
58 if (ce && (ce->hunk->type & NGX_HUNK_FILE)) { | |
59 file = ce->hunk; | |
60 ce = ce->next; | |
61 } | |
62 | |
63 /* create the trailer iovec */ | |
64 if (ce && ngx_hunk_in_memory_only(ce->hunk)) { | |
65 prev = NULL; | |
66 iov = NULL; | |
67 | |
68 /* create the iovec and coalesce the neighbouring chain entries */ | |
69 while (ce && ngx_hunk_in_memory_only(ce->hunk)) { | |
70 | |
71 if (prev == ce->hunk->pos) { | |
72 iov->iov_len += ce->hunk->last - ce->hunk->pos; | |
73 prev = ce->hunk->last; | |
74 | |
75 } else { | |
76 ngx_test_null(iov, ngx_push_array(&trailer), NGX_CHAIN_ERROR); | |
77 iov->iov_base = ce->hunk->pos; | |
78 iov->iov_len = ce->hunk->last - ce->hunk->pos; | |
79 prev = ce->hunk->last; | |
80 } | |
81 | |
82 ce = ce->next; | |
83 } | |
84 } | |
85 | |
86 if (file) { | |
87 if (setsockopt(c->fd, IPPROTO_TCP, TCP_CORK, | |
88 (const void *) &on, sizeof(int)) == -1) { | |
89 ngx_log_error(NGX_LOG_CRIT, c->log, err, | |
90 "setsockopt(TCP_CORK, 1) failed"); | |
91 return NGX_CHAIN_ERROR; | |
92 } | |
93 | |
94 | |
95 rc = sendfile(c->fd, file->file->fd, file->file_pos, | |
96 (size_t) (file->file_last - file->file_pos)); | |
97 | |
98 if (rc == -1) { | |
99 err = ngx_errno; | |
100 if (err == NGX_EAGAIN) { | |
101 ngx_log_error(NGX_LOG_INFO, c->log, err, "senfile() EAGAIN"); | |
102 | |
103 } else if (err == NGX_EINTR) { | |
104 ngx_log_error(NGX_LOG_INFO, c->log, err, "senfile() EINTR"); | |
105 | |
106 } else { | |
107 ngx_log_error(NGX_LOG_CRIT, c->log, err, "sendfile() failed"); | |
108 return NGX_CHAIN_ERROR; | |
109 } | |
110 } | |
111 | |
112 sent = rc > 0 ? rc : 0; | |
113 | |
114 #if (NGX_DEBUG_WRITE_CHAIN) | |
115 ngx_log_debug(c->log, "sendfile: %d, @%qd %d:%d" _ | |
116 rc _ file->file_pos _ sent _ | |
117 (size_t) (file->file_last - file->file_pos)); | |
118 #endif | |
119 | |
120 } else { | |
121 rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); | |
122 | |
123 if (rc == -1) { | |
124 err = ngx_errno; | |
125 if (err == NGX_EAGAIN) { | |
126 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); | |
127 | |
128 } else if (err == NGX_EINTR) { | |
129 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR"); | |
130 | |
131 } else { | |
132 ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed"); | |
133 return NGX_CHAIN_ERROR; | |
134 } | |
135 } | |
136 | |
137 sent = rc > 0 ? rc : 0; | |
138 | |
139 #if (NGX_DEBUG_WRITE_CHAIN) | |
140 ngx_log_debug(c->log, "writev: %d" _ sent); | |
141 #endif | |
142 } | |
143 | |
144 c->sent += sent; | |
145 | |
146 for (ce = in; ce && sent > 0; ce = ce->next) { | |
147 | |
148 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { | |
149 size = ce->hunk->last - ce->hunk->pos; | |
150 } else { | |
151 size = ce->hunk->file_last - ce->hunk->file_pos; | |
152 } | |
153 | |
154 if (sent >= size) { | |
155 sent -= size; | |
156 | |
157 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { | |
158 ce->hunk->pos = ce->hunk->last; | |
159 } | |
160 | |
161 if (ce->hunk->type & NGX_HUNK_FILE) { | |
162 ce->hunk->file_pos = ce->hunk->file_last; | |
163 } | |
164 | |
165 continue; | |
166 } | |
167 | |
168 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { | |
169 ce->hunk->pos += sent; | |
170 } | |
171 | |
172 if (ce->hunk->type & NGX_HUNK_FILE) { | |
173 ce->hunk->file_pos += sent; | |
174 } | |
175 | |
176 break; | |
177 } | |
178 | |
179 ngx_destroy_array(&trailer); | |
180 ngx_destroy_array(&header); | |
181 | |
182 return ce; | |
183 } | 214 } |