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 }