comparison src/event/ngx_event_pipe.c @ 4232:487ab473f393

Event pipe: fixes for complex protocols. 1. In ngx_event_pipe_write_chain_to_temp_file() make sure to fully write all shadow buffers up to last_shadow. With this change recycled buffers cannot appear in p->out anymore. This also fixes segmentation faults observed due to ngx_event_pipe_write_chain_to_temp() not freeing any raw buffers while still returning NGX_OK. 2. In ngx_event_pipe_write_to_downstream() we now properly check for busy size as a size of buffers, not a size of data in these buffers. This fixes situations where all available buffers became busy (including segmentation faults due to this). 3. The ngx_event_pipe_free_shadow_raw_buf() function is dropped. It's incorrect and not needed.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 31 Oct 2011 09:53:16 +0000
parents 6b9b7e7ac4a9
children aae172db7ac8
comparison
equal deleted inserted replaced
4231:d50883ff2433 4232:487ab473f393
13 static ngx_int_t ngx_event_pipe_read_upstream(ngx_event_pipe_t *p); 13 static ngx_int_t ngx_event_pipe_read_upstream(ngx_event_pipe_t *p);
14 static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p); 14 static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p);
15 15
16 static ngx_int_t ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p); 16 static ngx_int_t ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p);
17 static ngx_inline void ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf); 17 static ngx_inline void ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf);
18 static ngx_inline void ngx_event_pipe_free_shadow_raw_buf(ngx_chain_t **free,
19 ngx_buf_t *buf);
20 static ngx_int_t ngx_event_pipe_drain_chains(ngx_event_pipe_t *p); 18 static ngx_int_t ngx_event_pipe_drain_chains(ngx_event_pipe_t *p);
21 19
22 20
23 ngx_int_t 21 ngx_int_t
24 ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) 22 ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
574 572
575 for ( ;; ) { 573 for ( ;; ) {
576 if (p->out) { 574 if (p->out) {
577 cl = p->out; 575 cl = p->out;
578 576
579 if (cl->buf->recycled 577 if (cl->buf->recycled) {
580 && bsize + cl->buf->last - cl->buf->pos > p->busy_size) 578 ngx_log_error(NGX_LOG_ALERT, p->log, 0,
581 { 579 "recycled buffer in pipe out chain");
582 flush = 1;
583 break;
584 } 580 }
585 581
586 p->out = p->out->next; 582 p->out = p->out->next;
587
588 ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs, cl->buf);
589 583
590 } else if (!p->cacheable && p->in) { 584 } else if (!p->cacheable && p->in) {
591 cl = p->in; 585 cl = p->in;
592 586
593 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, 587 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0,
594 "pipe write buf ls:%d %p %z", 588 "pipe write buf ls:%d %p %z",
595 cl->buf->last_shadow, 589 cl->buf->last_shadow,
596 cl->buf->pos, 590 cl->buf->pos,
597 cl->buf->last - cl->buf->pos); 591 cl->buf->last - cl->buf->pos);
598 592
599 if (cl->buf->recycled 593 if (cl->buf->recycled && prev_last_shadow) {
600 && cl->buf->last_shadow 594 if (bsize + cl->buf->end - cl->buf->start > p->busy_size) {
601 && bsize + cl->buf->last - cl->buf->pos > p->busy_size) 595 flush = 1;
602 { 596 break;
603 if (!prev_last_shadow) {
604 p->in = p->in->next;
605
606 cl->next = NULL;
607
608 if (out) {
609 *ll = cl;
610 } else {
611 out = cl;
612 }
613 } 597 }
614 598
615 flush = 1; 599 bsize += cl->buf->end - cl->buf->start;
616 break;
617 } 600 }
618 601
619 prev_last_shadow = cl->buf->last_shadow; 602 prev_last_shadow = cl->buf->last_shadow;
620 603
621 p->in = p->in->next; 604 p->in = p->in->next;
622 605
623 } else { 606 } else {
624 break; 607 break;
625 }
626
627 if (cl->buf->recycled) {
628 bsize += cl->buf->last - cl->buf->pos;
629 } 608 }
630 609
631 cl->next = NULL; 610 cl->next = NULL;
632 611
633 if (out) { 612 if (out) {
701 static ngx_int_t 680 static ngx_int_t
702 ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) 681 ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
703 { 682 {
704 ssize_t size, bsize; 683 ssize_t size, bsize;
705 ngx_buf_t *b; 684 ngx_buf_t *b;
685 ngx_uint_t prev_last_shadow;
706 ngx_chain_t *cl, *tl, *next, *out, **ll, **last_free, fl; 686 ngx_chain_t *cl, *tl, *next, *out, **ll, **last_free, fl;
707 687
708 if (p->buf_to_file) { 688 if (p->buf_to_file) {
709 fl.buf = p->buf_to_file; 689 fl.buf = p->buf_to_file;
710 fl.next = p->in; 690 fl.next = p->in;
717 if (!p->cacheable) { 697 if (!p->cacheable) {
718 698
719 size = 0; 699 size = 0;
720 cl = out; 700 cl = out;
721 ll = NULL; 701 ll = NULL;
702 prev_last_shadow = 1;
722 703
723 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, 704 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
724 "pipe offset: %O", p->temp_file->offset); 705 "pipe offset: %O", p->temp_file->offset);
725 706
726 do { 707 do {
727 bsize = cl->buf->last - cl->buf->pos; 708 bsize = cl->buf->last - cl->buf->pos;
728 709
729 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, 710 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, p->log, 0,
730 "pipe buf %p, pos %p, size: %z", 711 "pipe buf ls:%d %p, pos %p, size: %z",
731 cl->buf->start, cl->buf->pos, bsize); 712 cl->buf->last_shadow, cl->buf->start,
732 713 cl->buf->pos, bsize);
733 if ((size + bsize > p->temp_file_write_size) 714
734 || (p->temp_file->offset + size + bsize > p->max_temp_file_size)) 715 if (prev_last_shadow
716 && ((size + bsize > p->temp_file_write_size)
717 || (p->temp_file->offset + size + bsize
718 > p->max_temp_file_size)))
735 { 719 {
736 break; 720 break;
737 } 721 }
722
723 prev_last_shadow = cl->buf->last_shadow;
738 724
739 size += bsize; 725 size += bsize;
740 ll = &cl->next; 726 ll = &cl->next;
741 cl = cl->next; 727 cl = cl->next;
742 728
911 897
912 buf->shadow = NULL; 898 buf->shadow = NULL;
913 } 899 }
914 900
915 901
916 static ngx_inline void
917 ngx_event_pipe_free_shadow_raw_buf(ngx_chain_t **free, ngx_buf_t *buf)
918 {
919 ngx_buf_t *s;
920 ngx_chain_t *cl, **ll;
921
922 if (buf->shadow == NULL) {
923 return;
924 }
925
926 for (s = buf->shadow; !s->last_shadow; s = s->shadow) { /* void */ }
927
928 ll = free;
929
930 for (cl = *free; cl; cl = cl->next) {
931 if (cl->buf == s) {
932 *ll = cl->next;
933 break;
934 }
935
936 if (cl->buf->shadow) {
937 break;
938 }
939
940 ll = &cl->next;
941 }
942 }
943
944
945 ngx_int_t 902 ngx_int_t
946 ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b) 903 ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b)
947 { 904 {
948 ngx_chain_t *cl; 905 ngx_chain_t *cl;
949 906