Mercurial > hg > nginx-vendor-1-0
comparison src/core/ngx_output_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 | cc9f381affaa |
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 #define NGX_NONE 1 | |
13 | |
14 | |
15 ngx_inline static ngx_int_t | |
16 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); | |
17 static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, | |
18 ngx_uint_t sendfile); | |
19 | |
20 | |
21 ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) | |
22 { | |
23 int rc, last; | |
24 size_t size, bsize; | |
25 ngx_chain_t *cl, *out, **last_out; | |
26 | |
27 /* | |
28 * the short path for the case when the ctx->in chain is empty | |
29 * and the incoming chain is empty too or it has the single buf | |
30 * that does not require the copy | |
31 */ | |
32 | |
33 if (ctx->in == NULL) { | |
34 | |
35 if (in == NULL) { | |
36 return ctx->output_filter(ctx->filter_ctx, in); | |
37 } | |
38 | |
39 if (in->next == NULL | |
40 && (!ngx_output_chain_need_to_copy(ctx, in->buf))) | |
41 { | |
42 return ctx->output_filter(ctx->filter_ctx, in); | |
43 } | |
44 } | |
45 | |
46 /* add the incoming buf to the chain ctx->in */ | |
47 | |
48 if (in) { | |
49 if (ngx_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) { | |
50 return NGX_ERROR; | |
51 } | |
52 } | |
53 | |
54 last = NGX_NONE; | |
55 out = NULL; | |
56 last_out = &out; | |
57 | |
58 for ( ;; ) { | |
59 | |
60 while (ctx->in) { | |
61 | |
62 /* | |
63 * cycle while there are the ctx->in bufs | |
64 * or there are the free output bufs to copy in | |
65 */ | |
66 | |
67 bsize = ngx_buf_size(ctx->in->buf); | |
68 | |
69 if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) { | |
70 | |
71 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, | |
72 "zero size buf"); | |
73 | |
74 ctx->in = ctx->in->next; | |
75 | |
76 continue; | |
77 } | |
78 | |
79 if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) { | |
80 | |
81 /* move the chain link to the output chain */ | |
82 | |
83 cl = ctx->in; | |
84 ctx->in = cl->next; | |
85 | |
86 *last_out = cl; | |
87 last_out = &cl->next; | |
88 cl->next = NULL; | |
89 | |
90 continue; | |
91 } | |
92 | |
93 if (ctx->buf == NULL) { | |
94 | |
95 /* get the free buf */ | |
96 | |
97 if (ctx->free) { | |
98 ctx->buf = ctx->free->buf; | |
99 ctx->free = ctx->free->next; | |
100 | |
101 } else if (out || ctx->allocated == ctx->bufs.num) { | |
102 | |
103 break; | |
104 | |
105 } else { | |
106 | |
107 size = ctx->bufs.size; | |
108 | |
109 if (ctx->in->buf->last_buf) { | |
110 | |
111 if (bsize < ctx->bufs.size) { | |
112 | |
113 /* | |
114 * allocate small temp buf for the small last buf | |
115 * or its small last part | |
116 */ | |
117 | |
118 size = bsize; | |
119 | |
120 } else if (ctx->bufs.num == 1 | |
121 && (bsize < ctx->bufs.size | |
122 + (ctx->bufs.size >> 2))) | |
123 { | |
124 /* | |
125 * allocate a temp buf that equals | |
126 * to the last buf if the last buf size is lesser | |
127 * than 1.25 of bufs.size and a temp buf is single | |
128 */ | |
129 | |
130 size = bsize; | |
131 } | |
132 } | |
133 | |
134 if (!(ctx->buf = ngx_create_temp_buf(ctx->pool, size))) { | |
135 return NGX_ERROR; | |
136 } | |
137 | |
138 ctx->buf->tag = ctx->tag; | |
139 ctx->buf->recycled = 1; | |
140 ctx->allocated++; | |
141 } | |
142 } | |
143 | |
144 rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf, | |
145 ctx->sendfile); | |
146 | |
147 if (rc == NGX_ERROR) { | |
148 return rc; | |
149 } | |
150 | |
151 if (rc == NGX_AGAIN) { | |
152 if (out) { | |
153 break; | |
154 } | |
155 | |
156 return rc; | |
157 } | |
158 | |
159 /* delete the completed buf from the ctx->in chain */ | |
160 | |
161 if (ngx_buf_size(ctx->in->buf) == 0) { | |
162 ctx->in = ctx->in->next; | |
163 } | |
164 | |
165 ngx_alloc_link_and_set_buf(cl, ctx->buf, ctx->pool, NGX_ERROR); | |
166 *last_out = cl; | |
167 last_out = &cl->next; | |
168 ctx->buf = NULL; | |
169 } | |
170 | |
171 if (out == NULL && last != NGX_NONE) { | |
172 return last; | |
173 } | |
174 | |
175 last = ctx->output_filter(ctx->filter_ctx, out); | |
176 | |
177 ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag); | |
178 last_out = &out; | |
179 | |
180 if (last == NGX_ERROR) { | |
181 return last; | |
182 } | |
183 } | |
184 } | |
185 | |
186 | |
187 ngx_inline static ngx_int_t | |
188 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) | |
189 { | |
190 if (ngx_buf_special(buf)) { | |
191 return 0; | |
192 } | |
193 | |
194 if (!ctx->sendfile) { | |
195 if (!ngx_buf_in_memory(buf)) { | |
196 return 1; | |
197 } | |
198 | |
199 buf->in_file = 0; | |
200 } | |
201 | |
202 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { | |
203 return 1; | |
204 } | |
205 | |
206 if (ctx->need_in_temp && (buf->memory || buf->mmap)) { | |
207 return 1; | |
208 } | |
209 | |
210 return 0; | |
211 } | |
212 | |
213 | |
214 static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, | |
215 ngx_uint_t sendfile) | |
216 { | |
217 size_t size; | |
218 ssize_t n; | |
219 | |
220 size = ngx_buf_size(src); | |
221 | |
222 if (size > (size_t) (dst->end - dst->pos)) { | |
223 size = dst->end - dst->pos; | |
224 } | |
225 | |
226 if (ngx_buf_in_memory(src)) { | |
227 ngx_memcpy(dst->pos, src->pos, size); | |
228 src->pos += size; | |
229 dst->last += size; | |
230 | |
231 if (src->in_file) { | |
232 src->file_pos += size; | |
233 } | |
234 | |
235 if (src->last_buf && src->pos == src->last) { | |
236 dst->last_buf = 1; | |
237 } | |
238 | |
239 } else { | |
240 n = ngx_read_file(src->file, dst->pos, size, src->file_pos); | |
241 | |
242 if (n == NGX_ERROR) { | |
243 return n; | |
244 } | |
245 | |
246 #if (NGX_FILE_AIO_READ) | |
247 if (n == NGX_AGAIN) { | |
248 return n; | |
249 } | |
250 #endif | |
251 | |
252 if ((size_t) n != size) { | |
253 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0, | |
254 ngx_read_file_n " reads only %d of %d from file", | |
255 n, size); | |
256 if (n == 0) { | |
257 return NGX_ERROR; | |
258 } | |
259 } | |
260 | |
261 src->file_pos += n; | |
262 dst->last += n; | |
263 | |
264 if (!sendfile) { | |
265 dst->in_file = 0; | |
266 } | |
267 | |
268 if (src->last_buf && src->file_pos == src->file_last) { | |
269 dst->last_buf = 1; | |
270 } | |
271 } | |
272 | |
273 return NGX_OK; | |
274 } | |
275 | |
276 | |
277 ngx_int_t ngx_chain_writer(void *data, ngx_chain_t *in) | |
278 { | |
279 ngx_chain_writer_ctx_t *ctx = data; | |
280 | |
281 ngx_chain_t *cl; | |
282 | |
283 | |
284 for (/* void */; in; in = in->next) { | |
285 | |
286 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, | |
287 "WRITER buf: %d", ngx_buf_size(in->buf)); | |
288 | |
289 ngx_alloc_link_and_set_buf(cl, in->buf, ctx->pool, NGX_ERROR); | |
290 *ctx->last = cl; | |
291 ctx->last = &cl->next; | |
292 } | |
293 | |
294 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, | |
295 "WRITER0: %X", ctx->out); | |
296 | |
297 ctx->out = ngx_send_chain(ctx->connection, ctx->out, ctx->limit); | |
298 | |
299 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, | |
300 "WRITER1: %X", ctx->out); | |
301 | |
302 if (ctx->out == NGX_CHAIN_ERROR) { | |
303 return NGX_ERROR; | |
304 } | |
305 | |
306 if (ctx->out == NULL) { | |
307 ctx->last = &ctx->out; | |
308 return NGX_OK; | |
309 } | |
310 | |
311 return NGX_AGAIN; | |
312 } |