comparison src/event/ngx_event_pipe.c @ 155:46eb23d9471d

nginx-0.0.1-2003-10-22-20:38:26 import
author Igor Sysoev <igor@sysoev.ru>
date Wed, 22 Oct 2003 16:38:26 +0000
parents eac26585476e
children fb61ba77beba
comparison
equal deleted inserted replaced
154:eac26585476e 155:46eb23d9471d
7 7
8 static int ngx_event_pipe_read_upstream(ngx_event_pipe_t *p); 8 static int ngx_event_pipe_read_upstream(ngx_event_pipe_t *p);
9 static int ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p); 9 static int ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p);
10 10
11 static int ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p); 11 static int ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p);
12 ngx_inline static void ngx_remove_shadow_links(ngx_hunk_t *hunk); 12 ngx_inline static void ngx_event_pipe_remove_shadow_links(ngx_hunk_t *hunk);
13 ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free, 13 ngx_inline static void ngx_event_pipe_free_shadow_raw_hunk(ngx_chain_t **free,
14 ngx_hunk_t *h); 14 ngx_hunk_t *h);
15 ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t **chain, 15 ngx_inline static void ngx_event_pipe_add_free_hunk(ngx_chain_t **chain,
16 ngx_chain_t *ce); 16 ngx_chain_t *cl);
17 static int ngx_drain_chains(ngx_event_pipe_t *p); 17 static int ngx_event_pipe_drain_chains(ngx_event_pipe_t *p);
18 18
19 19
20 int ngx_event_pipe(ngx_event_pipe_t *p, int do_write) 20 int ngx_event_pipe(ngx_event_pipe_t *p, int do_write)
21 { 21 {
22 for ( ;; ) { 22 for ( ;; ) {
55 55
56 int ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) 56 int ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
57 { 57 {
58 int n, rc, size; 58 int n, rc, size;
59 ngx_hunk_t *h; 59 ngx_hunk_t *h;
60 ngx_chain_t *chain, *ce, *te; 60 ngx_chain_t *chain, *cl, *tl;
61 61
62 if (p->upstream_eof || p->upstream_error || p->upstream_done) { 62 if (p->upstream_eof || p->upstream_error || p->upstream_done) {
63 return NGX_OK; 63 return NGX_OK;
64 } 64 }
65 65
129 ngx_test_null(h, ngx_create_temp_hunk(p->pool, 129 ngx_test_null(h, ngx_create_temp_hunk(p->pool,
130 p->bufs.size, 0, 0), 130 p->bufs.size, 0, 0),
131 NGX_ABORT); 131 NGX_ABORT);
132 p->hunks++; 132 p->hunks++;
133 133
134 ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); 134 ngx_alloc_link_and_set_hunk(tl, h, p->pool, NGX_ABORT);
135 chain = te; 135 chain = tl;
136 136
137 } else if (!p->cachable && p->downstream->write->ready) { 137 } else if (!p->cachable && p->downstream->write->ready) {
138 138
139 /* 139 /*
140 * if the hunks are not needed to be saved in a cache and 140 * if the hunks are not needed to be saved in a cache and
210 p->upstream_eof = 1; 210 p->upstream_eof = 1;
211 break; 211 break;
212 } 212 }
213 } 213 }
214 214
215 ce = chain; 215 cl = chain;
216 216
217 while (ce && n > 0) { 217 while (cl && n > 0) {
218 218
219 ngx_remove_shadow_links(ce->hunk); 219 ngx_event_pipe_remove_shadow_links(cl->hunk);
220 220
221 size = ce->hunk->end - ce->hunk->last; 221 size = cl->hunk->end - cl->hunk->last;
222 222
223 if (n >= size) { 223 if (n >= size) {
224 ce->hunk->last = ce->hunk->end; 224 cl->hunk->last = cl->hunk->end;
225 225
226 /* STUB */ ce->hunk->num = p->num++; 226 /* STUB */ cl->hunk->num = p->num++;
227 227
228 if (p->input_filter(p, ce->hunk) == NGX_ERROR) { 228 if (p->input_filter(p, cl->hunk) == NGX_ERROR) {
229 return NGX_ABORT; 229 return NGX_ABORT;
230 } 230 }
231 231
232 n -= size; 232 n -= size;
233 ce = ce->next; 233 cl = cl->next;
234 234
235 } else { 235 } else {
236 ce->hunk->last += n; 236 cl->hunk->last += n;
237 n = 0; 237 n = 0;
238 } 238 }
239 } 239 }
240 240
241 p->free_raw_hunks = ce; 241 p->free_raw_hunks = cl;
242 } 242 }
243 243
244 if ((p->upstream_eof || p->upstream_error) && p->free_raw_hunks) { 244 if ((p->upstream_eof || p->upstream_error) && p->free_raw_hunks) {
245 /* STUB */ p->free_raw_hunks->hunk->num = p->num++; 245 /* STUB */ p->free_raw_hunks->hunk->num = p->num++;
246 if (p->input_filter(p, p->free_raw_hunks->hunk) == NGX_ERROR) { 246 if (p->input_filter(p, p->free_raw_hunks->hunk) == NGX_ERROR) {
261 } 261 }
262 262
263 263
264 int ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) 264 int ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
265 { 265 {
266 size_t busy_len; 266 size_t bsize, to_write;
267 ngx_hunk_t *h; 267 ngx_hunk_t *h;
268 ngx_chain_t *out, **le, *ce, *te; 268 ngx_chain_t *out, **ll, *cl, *tl;
269 269
270 ngx_log_debug(p->log, "write downstream: %d" _ p->downstream->write->ready); 270 ngx_log_debug(p->log, "write downstream: %d" _ p->downstream->write->ready);
271 271
272 for ( ;; ) { 272 for ( ;; ) {
273 if (p->downstream_error) { 273 if (p->downstream_error) {
274 return ngx_drain_chains(p); 274 return ngx_event_pipe_drain_chains(p);
275 } 275 }
276 276
277 if ((p->upstream_eof || p->upstream_error || p->upstream_done) 277 if ((p->upstream_eof || p->upstream_error || p->upstream_done)
278 && p->out == NULL && p->in == NULL) 278 && p->out == NULL && p->in == NULL)
279 { 279 {
283 283
284 if (!p->downstream->write->ready) { 284 if (!p->downstream->write->ready) {
285 break; 285 break;
286 } 286 }
287 287
288 busy_len = 0; 288 /*
289 * bsize is the busy hunks size
290 * to_write is the size of data that to be written
291 */
292
293 bsize = 0;
294 to_write = 0;
289 295
290 if (!(p->upstream_eof || p->upstream_error || p->upstream_done)) { 296 if (!(p->upstream_eof || p->upstream_error || p->upstream_done)) {
291 /* calculate p->busy_len */ 297 for (cl = p->busy; cl; cl = cl->next) {
292 for (ce = p->busy; ce; ce = ce->next) { 298 bsize += cl->hunk->end - cl->hunk->start;
293 busy_len += ngx_hunk_size(ce->hunk); 299 to_write += ngx_hunk_size(cl->hunk);
294 } 300 }
295 } 301 }
296 302
297 out = NULL; 303 out = NULL;
298 le = NULL; 304 ll = NULL;
299 305
300 for ( ;; ) { 306 for ( ;; ) {
301 if (p->out) { 307 if (p->out) {
302 ce = p->out; 308 cl = p->out;
303 309
304 if (!(p->upstream_eof || p->upstream_error || p->upstream_done) 310 if (!(p->upstream_eof || p->upstream_error || p->upstream_done)
305 && (busy_len + ngx_hunk_size(ce->hunk) > p->max_busy_len)) 311 && (bsize + ngx_hunk_size(cl->hunk) > p->busy_size))
306 { 312 {
307 break; 313 break;
308 } 314 }
309 315
310 p->out = p->out->next; 316 p->out = p->out->next;
311 ngx_remove_shadow_free_raw_hunk(&p->free_raw_hunks, ce->hunk); 317 ngx_event_pipe_free_shadow_raw_hunk(&p->free_raw_hunks,
312 318 cl->hunk);
313 ngx_log_debug(p->log, "HUNK OUT: %d %x" _ ce->hunk->num _ ce->hunk->type); 319
320 ngx_log_debug(p->log, "HUNK OUT: %d %x" _ cl->hunk->num _ cl->hunk->type);
314 321
315 } else if (!p->cachable && p->in) { 322 } else if (!p->cachable && p->in) {
316 ce = p->in; 323 cl = p->in;
317 324
318 if (!(p->upstream_eof || p->upstream_error || p->upstream_done) 325 if (!(p->upstream_eof || p->upstream_error || p->upstream_done)
319 && (busy_len + ngx_hunk_size(ce->hunk) > p->max_busy_len)) 326 && (bsize + ngx_hunk_size(cl->hunk) > p->busy_size))
320 { 327 {
321 break; 328 break;
322 } 329 }
323 330
324 p->in = p->in->next; 331 p->in = p->in->next;
325 332
326 ngx_log_debug(p->log, "HUNK IN: %d" _ ce->hunk->num); 333 ngx_log_debug(p->log, "HUNK IN: %d" _ cl->hunk->num);
327 334
328 } else { 335 } else {
329 break; 336 break;
330 } 337 }
331 338
332 busy_len += ngx_hunk_size(ce->hunk); 339 bsize += ngx_hunk_size(cl->hunk);
333 ce->next = NULL; 340 cl->next = NULL;
334 ngx_chain_add_ce(out, le, ce); 341 ngx_chain_add_link(out, ll, cl);
335 } 342 }
336 343
337 if (out == NULL) { 344 if (out == NULL) {
338 ngx_log_debug(p->log, "no hunks to write BUSY: %d" _ busy_len); 345 ngx_log_debug(p->log, "no hunks to write BUSY: %d" _ to_write);
339 346
340 if (!p->upstream_blocked || busy_len == 0) { 347 if (!(p->upstream_blocked && to_write)) {
341 break; 348 break;
342 } 349 }
343 350
344 /* if the upstream is blocked then write the busy hunks */ 351 /*
352 * if the upstream is blocked and there are the busy hunks
353 * to write then write these hunks
354 */
345 } 355 }
346 356
347 if (p->output_filter(p->output_ctx, out) == NGX_ERROR) { 357 if (p->output_filter(p->output_ctx, out) == NGX_ERROR) {
348 p->downstream_error = 1; 358 p->downstream_error = 1;
349 359
350 /* handle the downstream error at the begin of the cycle. */ 360 /* handle the downstream error at the begin of a cycle */
351 361
352 continue; 362 continue;
353 } 363 }
354 364
355 ngx_chain_update_chains(&p->free, &p->busy, &out, p->tag); 365 ngx_chain_update_chains(&p->free, &p->busy, &out, p->tag);
356 366
357 for (ce = p->free; ce; ce = ce->next) { 367 for (cl = p->free; cl; cl = cl->next) {
358 368
359 /* add the free shadow raw hunk to p->free_raw_hunks */ 369 /* add the free shadow raw hunk to p->free_raw_hunks */
360 370
361 if (ce->hunk->type & NGX_HUNK_LAST_SHADOW) { 371 if (cl->hunk->type & NGX_HUNK_LAST_SHADOW) {
362 h = ce->hunk->shadow; 372 h = cl->hunk->shadow;
363 h->pos = h->last = h->start; 373 h->pos = h->last = h->start;
364 h->shadow = NULL; 374 h->shadow = NULL;
365 ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); 375 ngx_alloc_link_and_set_hunk(tl, h, p->pool, NGX_ABORT);
366 ngx_add_after_partially_filled_hunk(&p->free_raw_hunks, te); 376 ngx_event_pipe_add_free_hunk(&p->free_raw_hunks, tl);
367 377
368 ce->hunk->type &= ~NGX_HUNK_LAST_SHADOW; 378 cl->hunk->type &= ~NGX_HUNK_LAST_SHADOW;
369 } 379 }
370 ce->hunk->shadow = NULL; 380 cl->hunk->shadow = NULL;
371 381
372 if (p->cyclic_temp_file && (ce->hunk->type & NGX_HUNK_TEMP_FILE)) { 382 if (p->cyclic_temp_file && (cl->hunk->type & NGX_HUNK_TEMP_FILE)) {
373 383
374 /* reset p->temp_offset if all hunks had been sent */ 384 /* reset p->temp_offset if all hunks had been sent */
375 385
376 if (ce->hunk->file_last == p->temp_offset) { 386 if (cl->hunk->file_last == p->temp_offset) {
377 p->temp_offset = 0; 387 p->temp_offset = 0;
378 } 388 }
379 } 389 }
380 } 390 }
381 } 391 }
386 396
387 static int ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) 397 static int ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
388 { 398 {
389 int rc, size, hsize; 399 int rc, size, hsize;
390 ngx_hunk_t *h; 400 ngx_hunk_t *h;
391 ngx_chain_t *ce, *te, *next, *out, **le, **last_free; 401 ngx_chain_t *cl, *tl, *next, *out, **ll, **last_free;
392 402
393 ngx_log_debug(p->log, "write to file"); 403 ngx_log_debug(p->log, "write to file");
394 404
395 if (p->temp_file->fd == NGX_INVALID_FILE) { 405 if (p->temp_file->fd == NGX_INVALID_FILE) {
396 rc = ngx_create_temp_file(p->temp_file, p->temp_path, p->pool, 406 rc = ngx_create_temp_file(p->temp_file, p->temp_path, p->pool,
412 out = p->in; 422 out = p->in;
413 423
414 if (!p->cachable) { 424 if (!p->cachable) {
415 425
416 size = 0; 426 size = 0;
417 ce = p->in; 427 cl = p->in;
418 le = NULL; 428 ll = NULL;
419 429
420 ngx_log_debug(p->log, "offset: %d" _ p->temp_offset); 430 ngx_log_debug(p->log, "offset: %d" _ p->temp_offset);
421 431
422 do { 432 do {
423 hsize = ce->hunk->last - ce->hunk->pos; 433 hsize = cl->hunk->last - cl->hunk->pos;
424 434
425 ngx_log_debug(p->log, "hunk size: %d" _ hsize); 435 ngx_log_debug(p->log, "hunk size: %d" _ hsize);
426 436
427 if ((size + hsize > p->temp_file_write_size) 437 if ((size + hsize > p->temp_file_write_size)
428 || (p->temp_offset + size + hsize > p->max_temp_file_size)) 438 || (p->temp_offset + size + hsize > p->max_temp_file_size))
429 { 439 {
430 break; 440 break;
431 } 441 }
432 442
433 size += hsize; 443 size += hsize;
434 le = &ce->next; 444 ll = &cl->next;
435 ce = ce->next; 445 cl = cl->next;
436 446
437 } while (ce); 447 } while (cl);
438 448
439 ngx_log_debug(p->log, "size: %d" _ size); 449 ngx_log_debug(p->log, "size: %d" _ size);
440 450
441 if (ce) { 451 if (cl) {
442 p->in = ce; 452 p->in = cl;
443 *le = NULL; 453 *ll = NULL;
444 454
445 } else { 455 } else {
446 p->in = NULL; 456 p->in = NULL;
447 p->last_in = &p->in; 457 p->last_in = &p->in;
448 } 458 }
462 last_free = &(*last_free)->next) 472 last_free = &(*last_free)->next)
463 { 473 {
464 /* void */ 474 /* void */
465 } 475 }
466 476
467 for (ce = out; ce; ce = next) { 477 for (cl = out; cl; cl = next) {
468 next = ce->next; 478 next = cl->next;
469 ce->next = NULL; 479 cl->next = NULL;
470 480
471 h = ce->hunk; 481 h = cl->hunk;
472 h->file = p->temp_file; 482 h->file = p->temp_file;
473 h->file_pos = p->temp_offset; 483 h->file_pos = p->temp_offset;
474 p->temp_offset += h->last - h->pos; 484 p->temp_offset += h->last - h->pos;
475 h->file_last = p->temp_offset; 485 h->file_last = p->temp_offset;
476 486
478 h->type |= NGX_HUNK_FILE; 488 h->type |= NGX_HUNK_FILE;
479 } else { 489 } else {
480 h->type |= NGX_HUNK_FILE|NGX_HUNK_TEMP_FILE; 490 h->type |= NGX_HUNK_FILE|NGX_HUNK_TEMP_FILE;
481 } 491 }
482 492
483 ngx_chain_add_ce(p->out, p->last_out, ce); 493 ngx_chain_add_link(p->out, p->last_out, cl);
484 494
485 if (h->type & NGX_HUNK_LAST_SHADOW) { 495 if (h->type & NGX_HUNK_LAST_SHADOW) {
486 h->shadow->last = h->shadow->pos = h->shadow->start; 496 h->shadow->last = h->shadow->pos = h->shadow->start;
487 ngx_alloc_ce_and_set_hunk(te, h->shadow, p->pool, NGX_ABORT); 497 ngx_alloc_link_and_set_hunk(tl, h->shadow, p->pool, NGX_ABORT);
488 *last_free = te; 498 *last_free = tl;
489 last_free = &te->next; 499 last_free = &tl->next;
490 } 500 }
491 } 501 }
492 502
493 return NGX_OK; 503 return NGX_OK;
494 } 504 }
497 /* the copy input filter */ 507 /* the copy input filter */
498 508
499 int ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_hunk_t *hunk) 509 int ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_hunk_t *hunk)
500 { 510 {
501 ngx_hunk_t *h; 511 ngx_hunk_t *h;
502 ngx_chain_t *ce; 512 ngx_chain_t *cl;
503 513
504 if (hunk->pos == hunk->last) { 514 if (hunk->pos == hunk->last) {
505 return NGX_OK; 515 return NGX_OK;
506 } 516 }
507 517
517 h->shadow = hunk; 527 h->shadow = hunk;
518 h->tag = p->tag; 528 h->tag = p->tag;
519 h->type |= NGX_HUNK_LAST_SHADOW|NGX_HUNK_RECYCLED; 529 h->type |= NGX_HUNK_LAST_SHADOW|NGX_HUNK_RECYCLED;
520 hunk->shadow = h; 530 hunk->shadow = h;
521 531
522 ngx_alloc_ce_and_set_hunk(ce, h, p->pool, NGX_ERROR); 532 ngx_alloc_link_and_set_hunk(cl, h, p->pool, NGX_ERROR);
523 ngx_log_debug(p->log, "HUNK %d" _ h->num); 533 ngx_log_debug(p->log, "HUNK %d" _ h->num);
524 ngx_chain_add_ce(p->in, p->last_in, ce); 534 ngx_chain_add_link(p->in, p->last_in, cl);
525 535
526 return NGX_OK; 536 return NGX_OK;
527 } 537 }
528 538
529 539
530 ngx_inline static void ngx_remove_shadow_links(ngx_hunk_t *hunk) 540 ngx_inline static void ngx_event_pipe_remove_shadow_links(ngx_hunk_t *hunk)
531 { 541 {
532 ngx_hunk_t *h, *next; 542 ngx_hunk_t *h, *next;
533 543
534 if (hunk->shadow == NULL) { 544 if (hunk->shadow == NULL) {
535 return; 545 return;
552 562
553 hunk->shadow = NULL; 563 hunk->shadow = NULL;
554 } 564 }
555 565
556 566
557 ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free, 567 ngx_inline static void ngx_event_pipe_free_shadow_raw_hunk(ngx_chain_t **free,
558 ngx_hunk_t *h) 568 ngx_hunk_t *h)
559 { 569 {
560 ngx_hunk_t *s; 570 ngx_hunk_t *s;
561 ngx_chain_t *ce, **le; 571 ngx_chain_t *cl, **ll;
562 572
563 if (h->shadow == NULL) { 573 if (h->shadow == NULL) {
564 return; 574 return;
565 } 575 }
566 576
567 for (s = h->shadow; !(s->type & NGX_HUNK_LAST_SHADOW); s = s->shadow) { 577 for (s = h->shadow; !(s->type & NGX_HUNK_LAST_SHADOW); s = s->shadow) {
568 /* void */ 578 /* void */
569 } 579 }
570 580
571 le = free; 581 ll = free;
572 582
573 for (ce = *free ; ce; ce = ce->next) { 583 for (cl = *free ; cl; cl = cl->next) {
574 if (ce->hunk == s) { 584 if (cl->hunk == s) {
575 *le = ce->next; 585 *ll = cl->next;
576 break; 586 break;
577 } 587 }
578 588
579 if (ce->hunk->shadow) { 589 if (cl->hunk->shadow) {
580 break; 590 break;
581 } 591 }
582 592
583 le = &ce->next; 593 ll = &cl->next;
584 } 594 }
585 } 595 }
586 596
587 597
588 ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t **chain, 598 ngx_inline static void ngx_event_pipe_add_free_hunk(ngx_chain_t **chain,
589 ngx_chain_t *ce) 599 ngx_chain_t *cl)
590 { 600 {
591 if (*chain == NULL) { 601 if (*chain == NULL) {
592 *chain = ce; 602 *chain = cl;
593 return; 603 return;
594 } 604 }
595 605
596 if ((*chain)->hunk->pos != (*chain)->hunk->last) { 606 if ((*chain)->hunk->pos != (*chain)->hunk->last) {
597 ce->next = (*chain)->next; 607 cl->next = (*chain)->next;
598 (*chain)->next = ce; 608 (*chain)->next = cl;
599 609
600 } else { 610 } else {
601 ce->next = (*chain); 611 cl->next = (*chain);
602 (*chain) = ce; 612 (*chain) = cl;
603 } 613 }
604 } 614 }
605 615
606 616
607 static int ngx_drain_chains(ngx_event_pipe_t *p) 617 static int ngx_event_pipe_drain_chains(ngx_event_pipe_t *p)
608 { 618 {
609 ngx_hunk_t *h; 619 ngx_hunk_t *h;
610 ngx_chain_t *ce, *te; 620 ngx_chain_t *cl, *tl;
611 621
612 for ( ;; ) { 622 for ( ;; ) {
613 if (p->busy) { 623 if (p->busy) {
614 ce = p->busy; 624 cl = p->busy;
615 625
616 } else if (p->out) { 626 } else if (p->out) {
617 ce = p->out; 627 cl = p->out;
618 628
619 } else if (p->in) { 629 } else if (p->in) {
620 ce = p->in; 630 cl = p->in;
621 631
622 } else { 632 } else {
623 return NGX_OK; 633 return NGX_OK;
624 } 634 }
625 635
626 while (ce) { 636 while (cl) {
627 if (ce->hunk->type & NGX_HUNK_LAST_SHADOW) { 637 if (cl->hunk->type & NGX_HUNK_LAST_SHADOW) {
628 h = ce->hunk->shadow; 638 h = cl->hunk->shadow;
629 /* THINK NEEDED ??? */ h->pos = h->last = h->start; 639 h->pos = h->last = h->start;
630 h->shadow = NULL; 640 h->shadow = NULL;
631 ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); 641 ngx_alloc_link_and_set_hunk(tl, h, p->pool, NGX_ABORT);
632 ngx_add_after_partially_filled_hunk(&p->free_raw_hunks, te); 642 ngx_event_pipe_add_free_hunk(&p->free_raw_hunks, tl);
633 643
634 ce->hunk->type &= ~NGX_HUNK_LAST_SHADOW; 644 cl->hunk->type &= ~NGX_HUNK_LAST_SHADOW;
635 } 645 }
636 646
637 ce->hunk->shadow = NULL; 647 cl->hunk->shadow = NULL;
638 te = ce->next; 648 tl = cl->next;
639 ce->next = p->free; 649 cl->next = p->free;
640 p->free = ce; 650 p->free = cl;
641 ce = te; 651 cl = tl;
642 } 652 }
643 } 653 }
644 } 654 }