You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@arctic.org> on 1997/01/25 21:14:35 UTC

[PATCH] (updated) avoid bflush() when pipelining

Hold the presses!  Minor bug in my previous bflush() patch.  In my do {}
while loop around the select I forgot to re-initialize tv and fds (select
doesn't guarantee they'll contain anything useful if it returns -1 and
EINTR).  The fix was just to move the beginning of the do {} loop a few
lines higher.

This patch includes the change to send_fd_length as well.

Compiles and tests fine.

Dean

Index: buff.c
===================================================================
RCS file: /export/home/cvs/apache/src/buff.c,v
retrieving revision 1.14
diff -c -3 -r1.14 buff.c
*** buff.c	1997/01/20 04:28:07	1.14
--- buff.c	1997/01/25 20:11:59
***************
*** 402,407 ****
--- 402,438 ----
  }
  
  /*
+  * Tests if there is data to be read.  Returns 0 if there is data,
+  * -1 otherwise.
+  */
+ int
+ btestread(BUFF *fb)
+ {
+     fd_set fds;
+     struct timeval tv;
+     int rv;
+ 
+     /* the simple case, we've already got data in the buffer */
+     if( fb->incnt ) {
+ 	return( 0 );
+     }
+ 
+     /* otherwise see if the descriptor would block if we try to read it */
+     do {
+ 	FD_ZERO( &fds );
+ 	FD_SET( fb->fd_in, &fds );
+ 	tv.tv_sec = 0;
+ 	tv.tv_usec = 0;
+ #ifdef HPUX
+ 	rv = select( fb->fd_in + 1, (int *)&fds, NULL, NULL, &tv );
+ #else
+ 	rv = select( fb->fd_in + 1, &fds, NULL, NULL, &tv );
+ #endif
+     } while( rv < 0 && errno == EINTR );
+     return( rv == 1 ? 0 : -1 );
+ }
+ 
+ /*
   * Skip data until a linefeed character is read
   * Returns 1 on success, 0 if no LF found, or -1 on error
   */
***************
*** 469,474 ****
--- 500,533 ----
      else return buf[0];
  }
  
+ 
+ /*
+  * When doing chunked encodings we really have to write everything in the
+  * chunk before proceeding onto anything else.  This routine either writes
+  * nbytes and returns 0 or returns -1 indicating a failure.
+  *
+  * This is *seriously broken* if used on a non-blocking fd.  It will poll.
+  */
+ static int
+ write_it_all( int fd, const void *buf, int nbyte ) {
+ 
+     int i;
+ 
+     while( nbyte > 0 ) {
+ 	i = write( fd, buf, nbyte );
+ 	if( i == -1 ) {
+ 	    if( errno != EAGAIN && errno != EINTR ) {
+ 		return( -1 );
+ 	    }
+ 	} else {
+ 	    nbyte -= i;
+ 	    buf = i + (const char *)buf;
+ 	}
+     }
+     return( 0 );
+ }
+ 
+ 
  /*
   * A hook to write() that deals with chunking. This is really a protocol-
   * level issue, but we deal with it here because it's simpler; this is
***************
*** 476,493 ****
   * 2.0, using something like sfio stacked disciplines or BSD's funopen().
   */
  int bcwrite(BUFF *fb, const void *buf, int nbyte) {
-     int r;
  
      if (fb->flags & B_CHUNK) {
  	char chunksize[16];	/* Big enough for practically anything */
  
  	ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", nbyte);
! 	write(fb->fd, chunksize, strlen(chunksize));
      }
!     r = write(fb->fd, buf, nbyte);
!     if ((r > 0) && (fb->flags & B_CHUNK))
! 	write(fb->fd, "\015\012", 2);
!     return r;
  }
  
  /*
--- 535,557 ----
   * 2.0, using something like sfio stacked disciplines or BSD's funopen().
   */
  int bcwrite(BUFF *fb, const void *buf, int nbyte) {
  
      if (fb->flags & B_CHUNK) {
  	char chunksize[16];	/* Big enough for practically anything */
  
  	ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", nbyte);
! 	if( write_it_all(fb->fd, chunksize, strlen(chunksize)) == -1 ) {
! 	    return( -1 );
! 	}
! 	if( write_it_all(fb->fd, buf, nbyte) == -1 ) {
! 	    return( -1 );
! 	}
! 	if( write_it_all(fb->fd, "\015\012", 2) == -1 ) {
! 	    return( -1 );
! 	}
! 	return( nbyte );
      }
!     return( write(fb->fd, buf, nbyte) );
  }
  
  /*
***************
*** 573,579 ****
  /* we have emptied the file buffer. Now try to write the data from the
   * original buffer until there is less than bufsiz left
   */
!     while (nbyte > fb->bufsiz)
      {
  	do i = bcwrite(fb, buf, nbyte);
  	while (i == -1 && errno == EINTR);
--- 637,643 ----
  /* we have emptied the file buffer. Now try to write the data from the
   * original buffer until there is less than bufsiz left
   */
!     while (nbyte >= fb->bufsiz)
      {
  	do i = bcwrite(fb, buf, nbyte);
  	while (i == -1 && errno == EINTR);
***************
*** 611,617 ****
  int
  bflush(BUFF *fb)
  {
!     int i, j;
  
      if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0;
  
--- 675,681 ----
  int
  bflush(BUFF *fb)
  {
!     int i;
  
      if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0;
  
***************
*** 620,626 ****
      while (fb->outcnt > 0)
      {
  /* the buffer must be full */
- 	j = fb->outcnt;
  	do i = bcwrite(fb, fb->outbase, fb->outcnt);
  	while (i == -1 && errno == EINTR);
  	if (i > 0) fb->bytes_sent += i;
--- 684,689 ----
Index: buff.h
===================================================================
RCS file: /export/home/cvs/apache/src/buff.h,v
retrieving revision 1.9
diff -c -3 -r1.9 buff.h
*** buff.h	1997/01/01 18:10:15	1.9
--- buff.h	1997/01/25 20:11:59
***************
*** 120,125 ****
--- 120,126 ----
  extern int bvputs(BUFF *fb, ...);
  extern int bprintf(BUFF *fb,const char *fmt,...);
  extern int vbprintf(BUFF *fb,const char *fmt,va_list vlist);
+ extern int btestread(BUFF *fb);
  
  /* Internal routines */
  extern int bflsbuf(int c, BUFF *fb);
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.c,v
retrieving revision 1.110
diff -c -3 -r1.110 http_main.c
*** http_main.c	1997/01/24 21:06:33	1.110
--- http_main.c	1997/01/25 20:12:00
***************
*** 1673,1679 ****
          if (r) increment_counts(child_num,r,1);
  #endif
  	while (r && current_conn->keepalive) {
! 	    bflush(conn_io);
  	    destroy_pool(r->pool);
  	    (void)update_child_status (child_num, SERVER_BUSY_KEEPALIVE,
  	     (request_rec*)NULL);
--- 1673,1682 ----
          if (r) increment_counts(child_num,r,1);
  #endif
  	while (r && current_conn->keepalive) {
! 	    /* If there's no request waiting for us to read then flush the
! 	     * socket.  This is to avoid tickling a bug in older Netscape
! 	     * clients. */
! 	    if( btestread(conn_io) == -1 ) bflush(conn_io);
  	    destroy_pool(r->pool);
  	    (void)update_child_status (child_num, SERVER_BUSY_KEEPALIVE,
  	     (request_rec*)NULL);
***************
*** 2142,2148 ****
  	if (r) process_request (r); /* else premature EOF (ignore) */
  
          while (r && conn->keepalive) {
! 	    bflush(cio);
  	    destroy_pool(r->pool);
              r = read_request (conn);
              if (r) process_request (r);
--- 2145,2151 ----
  	if (r) process_request (r); /* else premature EOF (ignore) */
  
          while (r && conn->keepalive) {
! 	    if( btestread(cio) == -1 ) bflush(cio);
  	    destroy_pool(r->pool);
              r = read_request (conn);
              if (r) process_request (r);
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.c,v
retrieving revision 1.91
diff -c -3 -r1.91 http_protocol.c
*** http_protocol.c	1997/01/20 04:28:09	1.91
--- http_protocol.c	1997/01/25 20:12:00
***************
*** 1371,1378 ****
  	    o+=w;
          }
      }
- 
-     if (length > 0) bflush(c->client);
      
      SET_BYTES_SENT(r);
      return total_bytes_sent;
--- 1371,1376 ----


Re: [PATCH] (updated) avoid bflush() when pipelining

Posted by Alexei Kosut <ak...@nueva.pvt.k12.ca.us>.
On Sat, 25 Jan 1997, Dean Gaudet wrote:

> Hold the presses!  Minor bug in my previous bflush() patch.  In my do {}
> while loop around the select I forgot to re-initialize tv and fds (select
> doesn't guarantee they'll contain anything useful if it returns -1 and
> EINTR).  The fix was just to move the beginning of the do {} loop a few
> lines higher.
> 
> This patch includes the change to send_fd_length as well.
> 
> Compiles and tests fine.

Works for me. +1

-- 
________________________________________________________________________
Alexei Kosut <ak...@nueva.pvt.k12.ca.us>      The Apache HTTP Server
URL: http://www.nueva.pvt.k12.ca.us/~akosut/   http://www.apache.org/