comparison src/os/unix/ngx_linux_sendfile_chain.c @ 5913:8e903522c17a

Introduced the ngx_output_chain_to_iovec() function. It deduplicates code of the send chain functions and uses only preallocated memory, which completely solves the problem mentioned in d1bde5c3c5d2.
author Valentin Bartenev <vbart@nginx.com>
date Tue, 07 Oct 2014 11:38:57 +0400
parents de68ed551bfb
children ac3f78219f85
comparison
equal deleted inserted replaced
5912:de68ed551bfb 5913:8e903522c17a
30 ngx_chain_t * 30 ngx_chain_t *
31 ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) 31 ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
32 { 32 {
33 int rc, tcp_nodelay; 33 int rc, tcp_nodelay;
34 off_t size, send, prev_send, aligned, sent, fprev; 34 off_t size, send, prev_send, aligned, sent, fprev;
35 u_char *prev;
36 size_t file_size; 35 size_t file_size;
37 ngx_err_t err; 36 ngx_err_t err;
38 ngx_buf_t *file; 37 ngx_buf_t *file;
39 ngx_uint_t eintr; 38 ngx_uint_t eintr;
40 ngx_array_t header;
41 ngx_event_t *wev; 39 ngx_event_t *wev;
42 ngx_chain_t *cl; 40 ngx_chain_t *cl;
43 struct iovec *iov, headers[NGX_IOVS_PREALLOCATE]; 41 ngx_iovec_t header;
42 struct iovec headers[NGX_IOVS_PREALLOCATE];
44 #if (NGX_HAVE_SENDFILE64) 43 #if (NGX_HAVE_SENDFILE64)
45 off_t offset; 44 off_t offset;
46 #else 45 #else
47 int32_t offset; 46 int32_t offset;
48 #endif 47 #endif
61 } 60 }
62 61
63 62
64 send = 0; 63 send = 0;
65 64
66 header.elts = headers; 65 header.iovs = headers;
67 header.size = sizeof(struct iovec);
68 header.nalloc = NGX_IOVS_PREALLOCATE; 66 header.nalloc = NGX_IOVS_PREALLOCATE;
69 header.pool = c->pool;
70 67
71 for ( ;; ) { 68 for ( ;; ) {
72 file = NULL; 69 file = NULL;
73 file_size = 0; 70 file_size = 0;
74 eintr = 0; 71 eintr = 0;
75 prev_send = send; 72 prev_send = send;
76 73
77 header.nelts = 0;
78
79 prev = NULL;
80 iov = NULL;
81
82 /* create the iovec and coalesce the neighbouring bufs */ 74 /* create the iovec and coalesce the neighbouring bufs */
83 75
84 for (cl = in; cl && send < limit; cl = cl->next) { 76 cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log);
85 77
86 if (ngx_buf_special(cl->buf)) { 78 if (cl == NGX_CHAIN_ERROR) {
87 continue; 79 return NGX_CHAIN_ERROR;
88 } 80 }
89 81
90 #if 1 82 send += header.size;
91 if (!ngx_buf_in_memory(cl->buf) && !cl->buf->in_file) {
92 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
93 "zero size buf in sendfile "
94 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
95 cl->buf->temporary,
96 cl->buf->recycled,
97 cl->buf->in_file,
98 cl->buf->start,
99 cl->buf->pos,
100 cl->buf->last,
101 cl->buf->file,
102 cl->buf->file_pos,
103 cl->buf->file_last);
104
105 ngx_debug_point();
106
107 return NGX_CHAIN_ERROR;
108 }
109 #endif
110
111 if (!ngx_buf_in_memory_only(cl->buf)) {
112 break;
113 }
114
115 size = cl->buf->last - cl->buf->pos;
116
117 if (send + size > limit) {
118 size = limit - send;
119 }
120
121 if (prev == cl->buf->pos) {
122 iov->iov_len += (size_t) size;
123
124 } else {
125 if (header.nelts >= IOV_MAX) {
126 break;
127 }
128
129 iov = ngx_array_push(&header);
130 if (iov == NULL) {
131 return NGX_CHAIN_ERROR;
132 }
133
134 iov->iov_base = (void *) cl->buf->pos;
135 iov->iov_len = (size_t) size;
136 }
137
138 prev = cl->buf->pos + (size_t) size;
139 send += size;
140 }
141 83
142 /* set TCP_CORK if there is a header before a file */ 84 /* set TCP_CORK if there is a header before a file */
143 85
144 if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET 86 if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET
145 && header.nelts != 0 87 && header.count != 0
146 && cl 88 && cl
147 && cl->buf->in_file) 89 && cl->buf->in_file)
148 { 90 {
149 /* the TCP_CORK and TCP_NODELAY are mutually exclusive */ 91 /* the TCP_CORK and TCP_NODELAY are mutually exclusive */
150 92
204 } 146 }
205 } 147 }
206 148
207 /* get the file buf */ 149 /* get the file buf */
208 150
209 if (header.nelts == 0 && cl && cl->buf->in_file && send < limit) { 151 if (header.count == 0 && cl && cl->buf->in_file && send < limit) {
210 file = cl->buf; 152 file = cl->buf;
211 153
212 /* coalesce the neighbouring file bufs */ 154 /* coalesce the neighbouring file bufs */
213 155
214 do { 156 do {
281 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, 223 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
282 "sendfile: %d, @%O %O:%uz", 224 "sendfile: %d, @%O %O:%uz",
283 rc, file->file_pos, sent, file_size); 225 rc, file->file_pos, sent, file_size);
284 226
285 } else { 227 } else {
286 rc = writev(c->fd, header.elts, header.nelts); 228 rc = writev(c->fd, header.iovs, header.count);
287 229
288 if (rc == -1) { 230 if (rc == -1) {
289 err = ngx_errno; 231 err = ngx_errno;
290 232
291 switch (err) { 233 switch (err) {