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 }