You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by rb...@locus.apache.org on 2000/12/22 01:19:17 UTC

cvs commit: apr/network_io/unix sendrecv.c

rbb         00/12/21 16:19:17

  Modified:    .        CHANGES
               network_io/unix sendrecv.c
  Log:
  On FreeBSD, it is possible for the first call to sendfile to
  get EAGAIN, but still send some data.  This means that we cannot
  call sendfile and then check for EAGAIN, and then wait and call
  sendfile again.  If we do that, then we are likely to send the
  first chunk of data twice, once in the first call and once in the
  second.  If we are using a timed write, then we check to make sure
  we can send data before trying to send it.  This gets sendfile working
  on FreeBSD in Apache again.
  
  Revision  Changes    Path
  1.30      +8 -0      apr/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apr/CHANGES,v
  retrieving revision 1.29
  retrieving revision 1.30
  diff -u -r1.29 -r1.30
  --- CHANGES	2000/12/22 00:02:49	1.29
  +++ CHANGES	2000/12/22 00:19:14	1.30
  @@ -1,5 +1,13 @@
   Changes with APR b1
   
  +  *) On FreeBSD, it is possible for the first call to sendfile to
  +     get EAGAIN, but still send some data.  This means that we cannot
  +     call sendfile and then check for EAGAIN, and then wait and call
  +     sendfile again.  If we do that, then we are likely to send the
  +     first chunk of data twice, once in the first call and once in the
  +     second.  If we are using a timed write, then we check to make sure
  +     we can send data before trying to send it. [Ryan Bloom]
  +
     *) Cleanup to help Apache support programs build cleanly.
        [Cliff Woolley <cl...@yahoo.com>]
   
  
  
  
  1.52      +15 -22    apr/network_io/unix/sendrecv.c
  
  Index: sendrecv.c
  ===================================================================
  RCS file: /home/cvs/apr/network_io/unix/sendrecv.c,v
  retrieving revision 1.51
  retrieving revision 1.52
  diff -u -r1.51 -r1.52
  --- sendrecv.c	2000/11/17 04:19:18	1.51
  +++ sendrecv.c	2000/12/22 00:19:16	1.52
  @@ -412,6 +412,21 @@
       headerstruct.trl_cnt = hdtr->numtrailers;
   
       /* FreeBSD can send the headers/footers as part of the system call */
  +    if (sock->timeout > 0) {
  +        /* On FreeBSD, it is possible for the first call to sendfile to
  +         * get EAGAIN, but still send some data.  This means that we cannot
  +         * call sendfile and then check for EAGAIN, and then wait and call
  +         * sendfile again.  If we do that, then we are likely to send the
  +         * first chunk of data twice, once in the first call and once in the
  +         * second.  If we are using a timed write, then we check to make sure
  +         * we can send data before trying to send it.
  +         */
  +        apr_status_t arv = wait_for_io_or_timeout(sock, 0);
  +        if (arv != APR_SUCCESS) {
  +            *len = 0;
  +            return arv;
  +        }
  +    }
   
       do {
           if (bytes_to_send) {
  @@ -442,28 +457,6 @@
               }
           }
       } while (rv == -1 && errno == EINTR);
  -
  -    if (rv == -1 && 
  -        (errno == EAGAIN || errno == EWOULDBLOCK) && 
  -        sock->timeout > 0) {
  -	apr_status_t arv = wait_for_io_or_timeout(sock, 0);
  -	if (arv != APR_SUCCESS) {
  -	    *len = 0;
  -	    return arv;
  -	}
  -        else {
  -            do {
  -        	rv = sendfile(file->filedes,	/* open file descriptor of the file to be sent */
  -        		      sock->socketdes,	/* socket */
  -        		      *offset,	/* where in the file to start */
  -        		      (size_t) * len,	/* number of bytes to send */
  -        		      &headerstruct,	/* Headers/footers */
  -        		      &nbytes,	/* number of bytes written */
  -        		      flags	/* undefined, set to 0 */
  -        	    );
  -            } while (rv == -1 && errno == EINTR);
  -        }
  -    }
   
       (*len) = nbytes;
       if (rv == -1) {
  
  
  

Re: cvs commit: apr/network_io/unix sendrecv.c

Posted by rb...@covalent.net.
> Rather than waiting for IO to be possible, doesn't the sendfile() return the
> number of bytes written? In other words, you would get EAGAIN *and* bytes
> written. Thus, you know not to send that data again.
> 
> Seems like that would save a syscall for calls with timeout > 0.

There are a couple of problems with that.  If we know that some data has
been sent, then we have to figure out when that data ends, and re-send
from that location.  This duplicates logic that is already necessary in
the actual application.

The other option is to just try the sendfile, and if it sends anything,
just return, but if it doesn't then do the wait_or_timeout call.  This
complicates the code a bit, and in the case where we can't send
immediately, we end up with an extra syscall instead of removing one.

Basically, the approach I chose leverages logic that the application must
have regardless, and it means two syscalls for all cases, instead of one
syscall if the socket is available to write to, and three if it isn't.

This is really a toss up, but I chose to do it this way.  I am willing to
be convinced that the other way is better though.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------



Re: cvs commit: apr/network_io/unix sendrecv.c

Posted by Greg Stein <gs...@lyra.org>.
Rather than waiting for IO to be possible, doesn't the sendfile() return the
number of bytes written? In other words, you would get EAGAIN *and* bytes
written. Thus, you know not to send that data again.

Seems like that would save a syscall for calls with timeout > 0.

Cheers,
-g

On Fri, Dec 22, 2000 at 12:19:17AM -0000, rbb@locus.apache.org wrote:
> rbb         00/12/21 16:19:17
> 
>   Modified:    .        CHANGES
>                network_io/unix sendrecv.c
>   Log:
>   On FreeBSD, it is possible for the first call to sendfile to
>   get EAGAIN, but still send some data.  This means that we cannot
>   call sendfile and then check for EAGAIN, and then wait and call
>   sendfile again.  If we do that, then we are likely to send the
>   first chunk of data twice, once in the first call and once in the
>   second.  If we are using a timed write, then we check to make sure
>   we can send data before trying to send it.  This gets sendfile working
>   on FreeBSD in Apache again.
>   
>   Revision  Changes    Path
>   1.30      +8 -0      apr/CHANGES
>   
>   Index: CHANGES
>   ===================================================================
>   RCS file: /home/cvs/apr/CHANGES,v
>   retrieving revision 1.29
>   retrieving revision 1.30
>   diff -u -r1.29 -r1.30
>   --- CHANGES	2000/12/22 00:02:49	1.29
>   +++ CHANGES	2000/12/22 00:19:14	1.30
>   @@ -1,5 +1,13 @@
>    Changes with APR b1
>    
>   +  *) On FreeBSD, it is possible for the first call to sendfile to
>   +     get EAGAIN, but still send some data.  This means that we cannot
>   +     call sendfile and then check for EAGAIN, and then wait and call
>   +     sendfile again.  If we do that, then we are likely to send the
>   +     first chunk of data twice, once in the first call and once in the
>   +     second.  If we are using a timed write, then we check to make sure
>   +     we can send data before trying to send it. [Ryan Bloom]
>   +
>      *) Cleanup to help Apache support programs build cleanly.
>         [Cliff Woolley <cl...@yahoo.com>]
>    
>   
>   
>   
>   1.52      +15 -22    apr/network_io/unix/sendrecv.c
>   
>   Index: sendrecv.c
>   ===================================================================
>   RCS file: /home/cvs/apr/network_io/unix/sendrecv.c,v
>   retrieving revision 1.51
>   retrieving revision 1.52
>   diff -u -r1.51 -r1.52
>   --- sendrecv.c	2000/11/17 04:19:18	1.51
>   +++ sendrecv.c	2000/12/22 00:19:16	1.52
>   @@ -412,6 +412,21 @@
>        headerstruct.trl_cnt = hdtr->numtrailers;
>    
>        /* FreeBSD can send the headers/footers as part of the system call */
>   +    if (sock->timeout > 0) {
>   +        /* On FreeBSD, it is possible for the first call to sendfile to
>   +         * get EAGAIN, but still send some data.  This means that we cannot
>   +         * call sendfile and then check for EAGAIN, and then wait and call
>   +         * sendfile again.  If we do that, then we are likely to send the
>   +         * first chunk of data twice, once in the first call and once in the
>   +         * second.  If we are using a timed write, then we check to make sure
>   +         * we can send data before trying to send it.
>   +         */
>   +        apr_status_t arv = wait_for_io_or_timeout(sock, 0);
>   +        if (arv != APR_SUCCESS) {
>   +            *len = 0;
>   +            return arv;
>   +        }
>   +    }
>    
>        do {
>            if (bytes_to_send) {
>   @@ -442,28 +457,6 @@
>                }
>            }
>        } while (rv == -1 && errno == EINTR);
>   -
>   -    if (rv == -1 && 
>   -        (errno == EAGAIN || errno == EWOULDBLOCK) && 
>   -        sock->timeout > 0) {
>   -	apr_status_t arv = wait_for_io_or_timeout(sock, 0);
>   -	if (arv != APR_SUCCESS) {
>   -	    *len = 0;
>   -	    return arv;
>   -	}
>   -        else {
>   -            do {
>   -        	rv = sendfile(file->filedes,	/* open file descriptor of the file to be sent */
>   -        		      sock->socketdes,	/* socket */
>   -        		      *offset,	/* where in the file to start */
>   -        		      (size_t) * len,	/* number of bytes to send */
>   -        		      &headerstruct,	/* Headers/footers */
>   -        		      &nbytes,	/* number of bytes written */
>   -        		      flags	/* undefined, set to 0 */
>   -        	    );
>   -            } while (rv == -1 && errno == EINTR);
>   -        }
>   -    }
>    
>        (*len) = nbytes;
>        if (rv == -1) {
>   
>   
>   

-- 
Greg Stein, http://www.lyra.org/