You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dave Hill <dd...@laurel.zk3.dec.com> on 2000/07/13 02:59:33 UTC

ap_sendfile() impementation for Tru64 UNIX


I mentioned ap_sendfile was not available for Tru64 earlier and
said I would take a crack at it. Well, it got me interested,
and so here it is :-)

Attached is a diff for a proposed ap_sendfile for Tru64 unix. sendfile()
is only available on v5.0(a?) and later. I tested this outside of
Apache by building a wrapper program that sent a single file to a
listener program. Although this works, I did not really get to test the
error paths. Although I based this on the __linux__ flavor I am not
sure I really,truely understand some of the partial write/ error
cases/blocking cases. Code review by someone who understands better how
ap_sendfile fits into the whole would be a very good idea.


*** sendrecv.c.orig	Wed Jul 12 15:35:10 2000
--- sendrecv.c	Wed Jul 12 20:47:16 2000
***************
*** 633,638 ****
      }
      return APR_SUCCESS;
  }
  #else
! #endif /* __linux__, __FreeBSD__, __HPUX__, _AIX */
  #endif /* APR_HAS_SENDFILE */
--- 633,777 ----
      }
      return APR_SUCCESS;
  }
+ #elif defined(__osf__) && defined (__alpha)
+ /*
+  * ap_sendfile for Tru64 Unix. 
+  */
+ ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file,
+ 		    ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len,
+ 		    ap_int32_t flags)
+ {
+     off_t nbytes = 0;
+     int rv, i;
+     ap_status_t arv;
+     struct iovec headerstruct[2];
+     size_t bytes_to_send = *len;
+ 
+     /* Ignore flags for now. */
+     flags = 0;
+ 
+     /*
+      Tru64 can send 1 header and 1 trailer per sendfile().
+      with > 1, we have the choice to build 1 header/trailer or
+      to send them before/after the sendfile. I did the later.
+ 
+      headerstruct is a 2 iovec array with the first pointing
+      to the header, the second pointing to the trailer.
+      iov_len must be set to zero on any not being used.
+      */
+ 
+     if(hdtr->numheaders == 0) {
+ 	headerstruct[0].iov_len = 0;
+     } else if (hdtr->numheaders == 1) {
+ 	headerstruct[0].iov_base = hdtr->headers[0].iov_base;
+ 	headerstruct[0].iov_len = hdtr->headers[0].iov_len;
+     } else {
+ 	ap_size_t hdrbytes = 0;
+ 	/* sending them in bits.. if more than one header/trailer */
+ 	headerstruct[0].iov_len = 0;
+ 
+ 	arv = ap_sendv(sock, hdtr->headers, hdtr->numheaders, &hdrbytes);
+ 	if (arv != APR_SUCCESS) {
+ 	    *len = 0;
+ 	    return errno;
+ 	}
+ 
+ 	nbytes += hdrbytes;
+ 
+ 	/* If this was a partial write and we aren't doing timeouts, 
+ 	 * return now with the partial byte count; this is a non-blocking 
+ 	 * socket.
+ 	 */
+ 	if (sock->timeout <= 0) {
+ 	    ap_size_t total_hdrbytes = 0;
+ 	    for (i = 0; i < hdtr->numheaders; i++) {
+ 		total_hdrbytes += hdtr->headers[i].iov_len;
+ 	    }
+ 	    if (hdrbytes < total_hdrbytes) {
+ 		*len = hdrbytes;
+ 		return APR_SUCCESS;
+ 	    }
+ 	}
+     }
+ 
+     if(hdtr->numtrailers == 0) {
+ 	headerstruct[1].iov_len = 0;
+     } else if (hdtr->numtrailers == 1) {
+ 	headerstruct[1].iov_base = hdtr->trailers[0].iov_base;
+ 	headerstruct[1].iov_len = hdtr->trailers[0].iov_len;
+     } else {
+ 	/* we will send them after the file as more than one */
+ 	headerstruct[1].iov_len = 0;
+     }
+ 
+     if (bytes_to_send) {
+ 	/* We won't dare call sendfile() if we don't have
+ 	 * header or file bytes to send because bytes_to_send == 0
+ 	 * means send the whole file.
+ 	 */
+ 	do {
+ 	    rv = sendfile(
+ 		  sock->socketdes, /* socket */
+ 		  file->filedes,   /* file to be sent */
+ 		  *offset,         /* where in the file to start */
+ 		  bytes_to_send,   /* number of bytes to send */
+ 		  headerstruct,    /* Headers/footers */
+ 		  flags);          /* currently unused */
+ 	} while (rv == -1 && errno == EINTR);
+     } else 
+ 	rv = 0;
+ 
+     if (rv == -1 && 
+ 	(errno == EAGAIN || errno == EWOULDBLOCK) && 
+ 	sock->timeout > 0) {
+ 	ap_status_t arv = wait_for_io_or_timeout(sock, 0);
+ 
+ 	if (arv != APR_SUCCESS) {
+ 	    *len = 0;
+ 	    return arv;
+ 	}
+ 	else {
+ 	    do {
+ 		rv = sendfile(
+ 		  sock->socketdes, /* socket */
+ 		  file->filedes, /* file to be sent */
+ 		  *offset,       /* where in the file to start */
+ 		  bytes_to_send, /* number of bytes to send */
+ 		  headerstruct, /* Headers/footers */
+ 		  flags        /* undefined, set to 0 */
+ 		    );
+ 	    } while (rv == -1 && errno == EINTR);
+ 	}
+     }
+ 
+     if(rv != -1) {
+ 	nbytes += rv;
+     }
+ 
+     if((rv != -1) && (hdtr->numtrailers > 1)) {
+ 	ap_size_t trlbytes = 0;
+ 
+ 	/* send the trailers now */
+ 	arv = ap_sendv(sock, hdtr->trailers, hdtr->numtrailers, &trlbytes);
+ 	if (arv != APR_SUCCESS) {
+ 	    *len = 0;
+ 	    return errno;
+ 	}
+ 
+ 	nbytes += trlbytes;
+     }
+ 
+     /* 
+        question:
+        should this be the sum of all of them ?
+        sendfile returns a total byte count incl headers/trailers
+        but when headers/trailers is > 1 hdrbytes and trlbytes
+        will be non-zero
+     */
+     (*len) = nbytes;
+ 
+     return (rv < 0) ? errno : APR_SUCCESS;
+ }
  #else
! #endif /* __linux__, __FreeBSD__, __HPUX__, _AIX, Tru64/OSF1 */
  #endif /* APR_HAS_SENDFILE */


+-------------------------------------------------------------+
Dave Hill                             Unix Software Group
Mailstop: ZKO3-3/Y15                  
Digital Equipment Corp.               (603) 884-2985
110 Spit Brook Road         /\_/\     enet: ddhill@zk3.dec.com
Nashua, NH 03062-2698       (0_0)     
+-----------------------oOO--(_)--OOo-------------------------+


Re: ap_sendfile() impementation for Tru64 UNIX

Posted by Jeff Trawick <tr...@ibm.net>.
> Date: Wed, 12 Jul 2000 20:59:33 -0400 (EDT)
> From: Dave Hill  <dd...@laurel.zk3.dec.com>
> 
> I mentioned ap_sendfile was not available for Tru64 earlier and
> said I would take a crack at it. Well, it got me interested,
> and so here it is :-)

I've been playing in ap_sendfile() a bit lately (at least before a
recent vacation from which I just returned), so I'll look at applying
your patch. 

A couple of requests first:

1. how does it work with the existing test driver?

Try out src/lib/apr/test/testsf (the test-ap_sendfile program) in both
blocking and non-blocking modes.  

terminal 1: run "testsf server"
terminal 2: run "testsf client blocking"

repeat again, but in terminal 2 run "testsf client nonblocking"

2. source formatting

Can you try to format the source according to Apache conventions, or
at least a bit closer?  From http://dev.apache.org there is a link to
a very brief documentation showing the desired indentation.

Other comments:

1. timeout mode

Note that timeout mode is broken with all existing ap_sendfile()
implementations (and yours too).  Don't worry about it. When timeout
mode is working for the other implementations, testsf will hopefully
have been modified (if required; maybe not) to drive it properly.

2. your question

> +     /* 
> +        question:
> +        should this be the sum of all of them ?
> +        sendfile returns a total byte count incl headers/trailers
> +        but when headers/trailers is > 1 hdrbytes and trlbytes
> +        will be non-zero
> +     */
> +     (*len) = nbytes;

*len on output should include a count of all bytes sent (header bytes
 sent + file bytes sent + trailer bytes sent).

testsf will help you out on this matter.

Thanks,

Jeff

-- 
Jeff Trawick | trawick@ibm.net | PGP public key at web site:
     http://www.geocities.com/SiliconValley/Park/9289/
          Born in Roswell... married an alien...