comparison src/os/unix/ngx_freebsd_sendfile_chain.c @ 96:a23d010f356d

nginx-0.0.1-2003-05-27-16:18:54 import
author Igor Sysoev <igor@sysoev.ru>
date Tue, 27 May 2003 12:18:54 +0000
parents 8220378432a8
children a059e1aa65d4
comparison
equal deleted inserted replaced
95:b48066122884 96:a23d010f356d
1 1
2 #include <ngx_config.h> 2 #include <ngx_config.h>
3
4 #include <ngx_core.h> 3 #include <ngx_core.h>
5 #include <ngx_types.h>
6 #include <ngx_alloc.h>
7 #include <ngx_array.h>
8 #include <ngx_hunk.h>
9 #include <ngx_connection.h>
10 #include <ngx_sendv.h>
11 #include <ngx_sendfile.h>
12 #include <ngx_freebsd_init.h> 4 #include <ngx_freebsd_init.h>
5
6
7 /*
8 sendfile() often sends 4K pages over ethernet in 3 packets: 2x1460 and 1176
9 or in 6 packets: 5x1460 and 892. Besides although sendfile() allows
10 to pass the header and the trailer it never sends the header or the trailer
11 with the part of the file in one packet. So we use TCP_NOPUSH (similar
12 to Linux's TCP_CORK) to postpone the sending - it not only sends the header
13 and the first part of the file in one packet but also sends 4K pages
14 in the full packets.
15
16 The turning TCP_NOPUSH off flushes any pending data at least in FreeBSD 4.2,
17 although there's special fix in src/sys/netinet/tcp_usrreq.c just before
18 FreeBSD 4.5.
19 */
13 20
14 21
15 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) 22 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in)
16 { 23 {
17 int rc; 24 int rc, eintr, tcp_nopush;
18 char *prev; 25 char *prev;
19 size_t hsize, size; 26 size_t hsize, size;
20 off_t sent; 27 off_t sent;
21 struct iovec *iov; 28 struct iovec *iov;
22 struct sf_hdtr hdtr; 29 struct sf_hdtr hdtr;
23 ngx_err_t err; 30 ngx_err_t err;
24 ngx_array_t header, trailer; 31 ngx_array_t header, trailer;
25 ngx_hunk_t *file; 32 ngx_hunk_t *file;
26 ngx_chain_t *ce; 33 ngx_chain_t *ce, *tail;
27 34
28 ce = in; 35 tcp_nopush = 0;
29 file = NULL; 36
30 hsize = 0; 37 do {
31 38 ce = in;
32 ngx_init_array(header, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); 39 file = NULL;
33 ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); 40 hsize = 0;
34 41 eintr = 0;
35 /* create the header iovec */ 42
36 if (ngx_hunk_in_memory_only(ce->hunk)) { 43 ngx_init_array(header, c->pool, 10, sizeof(struct iovec),
37 prev = NULL; 44 NGX_CHAIN_ERROR);
38 iov = NULL; 45 ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec),
39 46 NGX_CHAIN_ERROR);
40 /* create the iovec and coalesce the neighbouring chain entries */ 47
41 while (ce && ngx_hunk_in_memory_only(ce->hunk)) { 48 /* create the header iovec */
42 49 if (ngx_hunk_in_memory_only(ce->hunk)) {
43 if (prev == ce->hunk->pos) { 50 prev = NULL;
44 iov->iov_len += ce->hunk->last - ce->hunk->pos; 51 iov = NULL;
45 prev = ce->hunk->last; 52
46 53 /* create the iovec and coalesce the neighbouring chain entries */
54 while (ce && ngx_hunk_in_memory_only(ce->hunk)) {
55
56 if (prev == ce->hunk->pos) {
57 iov->iov_len += ce->hunk->last - ce->hunk->pos;
58 prev = ce->hunk->last;
59
60 } else {
61 ngx_test_null(iov, ngx_push_array(&header),
62 NGX_CHAIN_ERROR);
63 iov->iov_base = ce->hunk->pos;
64 iov->iov_len = ce->hunk->last - ce->hunk->pos;
65 prev = ce->hunk->last;
66 }
67
68 hsize += ce->hunk->last - ce->hunk->pos;
69
70 ce = ce->next;
71 }
72 }
73
74 /* TODO: coalesce the neighbouring file hunks */
75 if (ce && (ce->hunk->type & NGX_HUNK_FILE)) {
76 file = ce->hunk;
77 ce = ce->next;
78 }
79
80 /* create the trailer iovec */
81 if (ce && ngx_hunk_in_memory_only(ce->hunk)) {
82 prev = NULL;
83 iov = NULL;
84
85 /* create the iovec and coalesce the neighbouring chain entries */
86 while (ce && ngx_hunk_in_memory_only(ce->hunk)) {
87
88 if (prev == ce->hunk->pos) {
89 iov->iov_len += ce->hunk->last - ce->hunk->pos;
90 prev = ce->hunk->last;
91
92 } else {
93 ngx_test_null(iov, ngx_push_array(&trailer),
94 NGX_CHAIN_ERROR);
95 iov->iov_base = ce->hunk->pos;
96 iov->iov_len = ce->hunk->last - ce->hunk->pos;
97 prev = ce->hunk->last;
98 }
99
100 ce = ce->next;
101 }
102 }
103
104 tail = ce;
105
106 if (file) {
107
108 if (tcp_nopush == 0) {
109 tcp_nopush = 1;
110 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NOPUSH,
111 (const void *) &tcp_nopush,
112 sizeof(int)) == -1)
113 {
114 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno,
115 "setsockopt(TCP_NO_PUSH) failed");
116 return NGX_CHAIN_ERROR;
117 }
118 }
119
120 hdtr.headers = (struct iovec *) header.elts;
121 hdtr.hdr_cnt = header.nelts;
122 hdtr.trailers = (struct iovec *) trailer.elts;
123 hdtr.trl_cnt = trailer.nelts;
124
125 if (ngx_freebsd_sendfile_nbytes_bug == 0) {
126 hsize = 0;
127 }
128
129 rc = sendfile(file->file->fd, c->fd, file->file_pos,
130 (size_t) (file->file_last - file->file_pos) + hsize,
131 &hdtr, &sent, 0);
132
133 if (rc == -1) {
134 err = ngx_errno;
135
136 if (err == NGX_EINTR) {
137 eintr = 1;
138 }
139
140 if (err == NGX_EAGAIN || err == NGX_EINTR) {
141 ngx_log_error(NGX_LOG_INFO, c->log, err,
142 "sendfile() sent only %qd bytes", sent);
143
144 } else {
145 ngx_log_error(NGX_LOG_CRIT, c->log, err,
146 "sendfile() failed");
147 return NGX_CHAIN_ERROR;
148 }
149 }
150
151 #if (NGX_DEBUG_WRITE_CHAIN)
152 ngx_log_debug(c->log, "sendfile: %d, @%qd %qd:%d" _
153 rc _ file->file_pos _ sent _
154 (size_t) (file->file_last - file->file_pos) + hsize);
155 #endif
156
157 } else {
158 rc = writev(c->fd, (struct iovec *) header.elts, header.nelts);
159
160 if (rc == -1) {
161 err = ngx_errno;
162 if (err == NGX_EAGAIN) {
163 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN");
164
165 } else if (err == NGX_EINTR) {
166 eintr = 1;
167 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR");
168
169 } else {
170 ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed");
171 return NGX_CHAIN_ERROR;
172 }
173 }
174
175 sent = rc > 0 ? rc : 0;
176
177 #if (NGX_DEBUG_WRITE_CHAIN)
178 ngx_log_debug(c->log, "writev: %qd" _ sent);
179 #endif
180 }
181
182 c->sent += sent;
183
184 for (ce = in; ce && sent > 0; ce = ce->next) {
185
186 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
187 size = ce->hunk->last - ce->hunk->pos;
47 } else { 188 } else {
48 ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR); 189 size = ce->hunk->file_last - ce->hunk->file_pos;
49 iov->iov_base = ce->hunk->pos; 190 }
50 iov->iov_len = ce->hunk->last - ce->hunk->pos; 191
51 prev = ce->hunk->last; 192 if (sent >= size) {
52 } 193 sent -= size;
53 194
54 if (ngx_freebsd_sendfile_nbytes_bug) { 195 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
55 hsize += ce->hunk->last - ce->hunk->pos; 196 ce->hunk->pos = ce->hunk->last;
56 } 197 }
57 198
58 ce = ce->next; 199 if (ce->hunk->type & NGX_HUNK_FILE) {
200 ce->hunk->file_pos = ce->hunk->file_last;
201 }
202
203 continue;
204 }
205
206 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
207 ce->hunk->pos += sent;
208 }
209
210 if (ce->hunk->type & NGX_HUNK_FILE) {
211 ce->hunk->file_pos += sent;
212 }
213
214 break;
215 }
216
217 ngx_destroy_array(&trailer);
218 ngx_destroy_array(&header);
219
220 in = ce;
221
222 } while ((tail && tail == ce) || eintr);
223
224 if (tcp_nopush == 1) {
225 tcp_nopush = 0;
226 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NOPUSH,
227 (const void *) &tcp_nopush,
228 sizeof(int)) == -1)
229 {
230 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno,
231 "setsockopt(!TCP_NO_PUSH) failed");
232 return NGX_CHAIN_ERROR;
59 } 233 }
60 } 234 }
61
62 /* TODO: coalesce the neighbouring file hunks */
63 if (ce && (ce->hunk->type & NGX_HUNK_FILE)) {
64 file = ce->hunk;
65 ce = ce->next;
66 }
67
68 /* create the trailer iovec */
69 if (ce && ngx_hunk_in_memory_only(ce->hunk)) {
70 prev = NULL;
71 iov = NULL;
72
73 /* create the iovec and coalesce the neighbouring chain entries */
74 while (ce && ngx_hunk_in_memory_only(ce->hunk)) {
75
76 if (prev == ce->hunk->pos) {
77 iov->iov_len += ce->hunk->last - ce->hunk->pos;
78 prev = ce->hunk->last;
79
80 } else {
81 ngx_test_null(iov, ngx_push_array(&trailer), NGX_CHAIN_ERROR);
82 iov->iov_base = ce->hunk->pos;
83 iov->iov_len = ce->hunk->last - ce->hunk->pos;
84 prev = ce->hunk->last;
85 }
86
87 ce = ce->next;
88 }
89 }
90
91 if (file) {
92 hdtr.headers = (struct iovec *) header.elts;
93 hdtr.hdr_cnt = header.nelts;
94 hdtr.trailers = (struct iovec *) trailer.elts;
95 hdtr.trl_cnt = trailer.nelts;
96
97 rc = sendfile(file->file->fd, c->fd, file->file_pos,
98 (size_t) (file->file_last - file->file_pos) + hsize,
99 &hdtr, &sent, 0);
100
101 if (rc == -1) {
102 err = ngx_errno;
103 if (err == NGX_EAGAIN || err == NGX_EINTR) {
104 ngx_log_error(NGX_LOG_INFO, c->log, err,
105 "sendfile() sent only %qd bytes", sent);
106
107 } else {
108 ngx_log_error(NGX_LOG_CRIT, c->log, err, "sendfile() failed");
109 return NGX_CHAIN_ERROR;
110 }
111 }
112
113 #if (NGX_DEBUG_WRITE_CHAIN)
114 ngx_log_debug(c->log, "sendfile: %d, @%qd %qd:%d" _
115 rc _ file->file_pos _ sent _
116 (size_t) (file->file_last - file->file_pos) + hsize);
117 #endif
118
119 } else {
120 rc = writev(c->fd, (struct iovec *) header.elts, header.nelts);
121
122 if (rc == -1) {
123 err = ngx_errno;
124 if (err == NGX_EAGAIN) {
125 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN");
126
127 } else if (err == NGX_EINTR) {
128 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR");
129
130 } else {
131 ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed");
132 return NGX_CHAIN_ERROR;
133 }
134 }
135
136 sent = rc > 0 ? rc : 0;
137 }
138
139 #if (NGX_DEBUG_WRITE_CHAIN)
140 ngx_log_debug(c->log, "sendv: %qd" _ sent);
141 #endif
142
143 c->sent += sent;
144
145 for (ce = in; ce && sent > 0; ce = ce->next) {
146
147 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
148 size = ce->hunk->last - ce->hunk->pos;
149 } else {
150 size = ce->hunk->file_last - ce->hunk->file_pos;
151 }
152
153 if (sent >= size) {
154 sent -= size;
155
156 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
157 ce->hunk->pos = ce->hunk->last;
158 }
159
160 if (ce->hunk->type & NGX_HUNK_FILE) {
161 ce->hunk->file_pos = ce->hunk->file_last;
162 }
163
164 continue;
165 }
166
167 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
168 ce->hunk->pos += sent;
169 }
170
171 if (ce->hunk->type & NGX_HUNK_FILE) {
172 ce->hunk->file_pos += sent;
173 }
174
175 break;
176 }
177
178 ngx_destroy_array(&trailer);
179 ngx_destroy_array(&header);
180 235
181 return ce; 236 return ce;
182 } 237 }