commit logging is broken. So I'm posting this by hand.
I just committed this patch, which is essentially the patch which I posted
a few days ago for buff.c. I went line by line comparing it with the 1.2
buff.c and I think we've got all the 1.2 fixes in here now, plus the newer
1.3 stuff.
Dean
Index: buff.c
===================================================================
RCS file: /export/home/cvs/apache/src/buff.c,v
retrieving revision 1.42
diff -u -r1.42 buff.c
--- buff.c 1997/08/02 00:58:26 1.42
+++ buff.c 1997/08/08 07:54:45
@@ -190,6 +190,7 @@
#endif /* WIN32 */
+/* the lowest level reading primitive */
static inline int buff_read (BUFF *fb, void *buf, int nbyte)
{
int rv;
@@ -208,6 +209,7 @@
return rv;
}
+/* the lowest level writing primitive */
static inline int buff_write (BUFF *fb, const void *buf, int nbyte)
{
int rv;
@@ -465,27 +467,37 @@
}
#endif
-static int
+
+API_EXPORT(void) bhalfduplex (BUFF *fb)
+{
+ int rv;
+ fd_set fds;
+ struct timeval tv;
+
+ if (fb->incnt > 0) {
+ return;
+ }
+ /* test for a block */
+ do {
+ FD_ZERO( &fds );
+ FD_SET( fb->fd_in, &fds );
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ rv = ap_select( fb->fd_in + 1, &fds, NULL, NULL, &tv );
+ } while( rv < 0 && errno == EINTR );
+ /* treat any error as if it would block as well */
+ if( rv != 1 ) {
+ bflush(fb);
+ }
+}
+
+static inline int
saferead_guts(BUFF *fb, void *buf, int nbyte)
{
int rv;
if( fb->flags & B_SAFEREAD ) {
- fd_set fds;
- struct timeval tv;
-
- /* test for a block */
- do {
- FD_ZERO( &fds );
- FD_SET( fb->fd_in, &fds );
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- rv = ap_select( fb->fd_in + 1, &fds, NULL, NULL, &tv );
- } while( rv < 0 && errno == EINTR );
- /* treat any error as if it would block as well */
- if( rv != 1 ) {
- bflush(fb);
- }
+ bhalfduplex (fb);
}
do {
rv = buff_read (fb, buf, nbyte);
@@ -529,6 +541,25 @@
}
#endif
+
+/* A wrapper around saferead which does error checking and EOF checking
+ * yeah, it's confusing, this calls saferead, which calls buff_read...
+ * and then there's the SFIO case. Note that saferead takes care
+ * of EINTR.
+ */
+static int read_with_errors (BUFF *fb, void *buf, int nbyte)
+{
+ int rv;
+
+ rv = saferead (fb, buf, nbyte);
+ if (rv == 0) {
+ fb->flags |= B_EOF;
+ } else if (rv == -1 && errno != EAGAIN) {
+ doerror (fb, B_RD);
+ }
+ return rv;
+}
+
/*
* Read up to nbyte bytes into buf.
* If fewer than byte bytes are currently available, then return those.
@@ -551,9 +582,7 @@
fb->inptr += i;
return i;
}
- i = saferead( fb, buf, nbyte );
- if (i == 0) fb->flags |= B_EOF;
- if (i == -1 && errno != EAGAIN) doerror(fb, B_RD);
+ i = read_with_errors (fb, buf, nbyte);
return i;
}
@@ -577,33 +606,20 @@
if (fb->flags & B_EOF) return nrd;
/* do a single read */
- if (nbyte >= fb->bufsiz)
- {
+ if (nbyte >= fb->bufsiz) {
/* read directly into buffer */
- i = saferead( fb, buf, nbyte );
- if (i == -1)
- {
- if (nrd == 0)
- {
- if (errno != EAGAIN) doerror(fb, B_RD);
- return -1;
- }
- else return nrd;
- } else if (i == 0) fb->flags |= B_EOF;
- } else
- {
+ i = read_with_errors (fb, buf, nbyte);
+ if (i == -1) {
+ return nrd ? nrd : -1;
+ }
+ }
+ else {
/* read into hold buffer, then memcpy */
fb->inptr = fb->inbase;
- i = saferead( fb, fb->inptr, fb->bufsiz );
- if (i == -1)
- {
- if (nrd == 0)
- {
- if (errno != EAGAIN) doerror(fb, B_RD);
- return -1;
- }
- else return nrd;
- } else if (i == 0) fb->flags |= B_EOF;
+ i = read_with_errors (fb, fb->inptr, fb->bufsiz);
+ if (i == -1) {
+ return nrd ? nrd : -1;
+ }
fb->incnt = i;
if (i > nbyte) i = nbyte;
memcpy(buf, fb->inptr, i);
@@ -654,23 +670,13 @@
fb->inptr = fb->inbase;
fb->incnt = 0;
if (fb->flags & B_EOF) break;
- i = saferead( fb, fb->inptr, fb->bufsiz );
- if (i == -1)
- {
+ i = read_with_errors (fb, fb->inptr, fb->bufsiz);
+ if (i == -1) {
buff[ct] = '\0';
- if (ct == 0)
- {
- if (errno != EAGAIN) doerror(fb, B_RD);
- return -1;
- }
- else return ct;
+ return ct ? ct : -1;
}
fb->incnt = i;
- if (i == 0)
- {
- fb->flags |= B_EOF;
- break; /* EOF */
- }
+ if (i == 0) break; /* EOF */
i = 0;
continue; /* restart with the new data */
}
@@ -724,18 +730,11 @@
if (fb->flags & B_EOF)
return 0;
- i = saferead( fb, fb->inptr, fb->bufsiz );
-
- if (i == -1) {
- if (errno != EAGAIN)
- doerror(fb, B_RD);
- return -1;
- }
- if (i == 0) {
- fb->flags |= B_EOF;
- return 0; /* EOF */
- }
- else fb->incnt = i;
+ i = read_with_errors (fb, fb->inptr, fb->bufsiz);
+ if (i <= 0) {
+ return i;
+ }
+ fb->incnt = i;
}
*buff = fb->inptr[0];
@@ -773,10 +772,8 @@
fb->inptr = fb->inbase;
fb->incnt = 0;
if (fb->flags & B_EOF) return 0;
- i = saferead( fb, fb->inptr, fb->bufsiz );
- if (i == 0) fb->flags |= B_EOF;
- if (i == -1 && errno != EAGAIN) doerror(fb, B_RD);
- if (i == 0 || i == -1) return i;
+ i = read_with_errors (fb, fb->inptr, fb->bufsiz);
+ if (i <= 0) return i;
fb->incnt = i;
}
}
@@ -813,6 +810,8 @@
* nbytes and returns 0 or returns -1 indicating a failure.
*
* This is *seriously broken* if used on a non-blocking fd. It will poll.
+ *
+ * Deals with calling doerror and setting bytes_sent.
*/
static int
write_it_all(BUFF *fb, const void *buf, int nbyte)
@@ -823,15 +822,17 @@
return -1;
while (nbyte > 0) {
- i = buff_write( fb, buf, nbyte );
+ i = buff_write (fb, buf, nbyte);
if (i < 0) {
if (errno != EAGAIN && errno != EINTR) {
+ doerror (fb, B_WR);
return -1;
}
}
else {
nbyte -= i;
buf = i + (const char *)buf;
+ fb->bytes_sent += i;
}
if (fb->flags & B_EOUT)
return -1;
@@ -841,8 +842,10 @@
#ifndef NO_WRITEV
-/* similar to previous, but uses writev. Note that it modifies vec.
+/* Similar to previous, but uses writev. Note that it modifies vec.
* return 0 if successful, -1 otherwise.
+ *
+ * Deals with doerror() and bytes_sent.
*/
static int writev_it_all (BUFF *fb, struct iovec *vec, int nvec)
{
@@ -851,11 +854,18 @@
/* while it's nice an easy to build the vector and crud, it's painful
* to deal with a partial writev()
*/
- for( i = 0; i < nvec; ) {
+ i = 0;
+ while (i < nvec) {
do rv = writev( fb->fd, &vec[i], nvec - i );
- while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
- if (rv == -1)
+ while (rv == -1 && (errno == EINTR || errno == EAGAIN)
+ && !(fb->flags & B_EOUT));
+ if (rv == -1) {
+ if (errno != EINTR && errno != EAGAIN) {
+ doerror (fb, B_WR);
+ }
return -1;
+ }
+ fb->bytes_sent += rv;
/* recalculate vec to deal with partial writes */
while (rv > 0) {
if (rv < vec[i].iov_len) {
@@ -878,12 +888,37 @@
}
#endif
+/* A wrapper for buff_write which deals with error conditions and
+ * bytes_sent. Also handles non-blocking writes.
+ */
+static int write_with_errors (BUFF *fb, const void *buf, int nbyte)
+{
+ int rv;
+
+ do rv = buff_write(fb, buf, nbyte);
+ while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+ if (rv == -1) {
+ if (errno != EAGAIN) {
+ doerror (fb, B_WR);
+ }
+ return -1;
+ } else if (rv == 0) {
+ errno = EAGAIN;
+ return -1;
+ }
+ fb->bytes_sent += rv;
+ return rv;
+}
+
/*
* 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
* an interim solution pending a complete rewrite of all this stuff in
* 2.0, using something like sfio stacked disciplines or BSD's funopen().
+ *
+ * Can be used on non-blocking descriptors, but only if they're not chunked.
+ * Deals with doerror() and bytes_sent.
*/
static int
bcwrite(BUFF *fb, const void *buf, int nbyte)
@@ -897,7 +932,7 @@
return -1;
if (!(fb->flags & B_CHUNK)) {
- return buff_write(fb, buf, nbyte);
+ return write_with_errors (fb, buf, nbyte);
}
#ifdef NO_WRITEV
@@ -941,21 +976,27 @@
if (fb->flags & B_CHUNK) {
end_chunk(fb);
}
- vec[0].iov_base = (void *)fb->outbase;
- vec[0].iov_len = fb->outcnt;
+ nvec = 0;
+ if (fb->outcnt > 0) {
+ vec[nvec].iov_base = (void *)fb->outbase;
+ vec[nvec].iov_len = fb->outcnt;
+ ++nvec;
+ }
if (fb->flags & B_CHUNK) {
- vec[1].iov_base = chunksize;
- vec[1].iov_len = ap_snprintf (chunksize, sizeof(chunksize),
+ vec[nvec].iov_base = chunksize;
+ vec[nvec].iov_len = ap_snprintf (chunksize, sizeof(chunksize),
"%x\015\012", nbyte);
- vec[2].iov_base = (void *)buf;
- vec[2].iov_len = nbyte;
- vec[3].iov_base = "\r\n";
- vec[3].iov_len = 2;
- nvec = 4;
+ ++nvec;
+ vec[nvec].iov_base = (void *)buf;
+ vec[nvec].iov_len = nbyte;
+ ++nvec;
+ vec[nvec].iov_base = "\r\n";
+ vec[nvec].iov_len = 2;
+ ++nvec;
} else {
- vec[1].iov_base = (void *)buf;
- vec[1].iov_len = nbyte;
- nvec = 2;
+ vec[nvec].iov_base = (void *)buf;
+ vec[nvec].iov_len = nbyte;
+ ++nvec;
}
fb->outcnt = 0;
@@ -978,26 +1019,10 @@
if (fb->flags & (B_WRERR|B_EOUT)) return -1;
if (nbyte == 0) return 0;
- if (!(fb->flags & B_WR))
- {
+ if (!(fb->flags & B_WR)) {
/* unbuffered write -- have to use bcwrite since we aren't taking care
* of chunking any other way */
- do i = bcwrite(fb, buf, nbyte);
- while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
- if (i == 0) { /* return of 0 means non-blocking */
- errno = EAGAIN;
- return -1;
- }
- else if (i < 0) {
- if (errno != EAGAIN)
- doerror(fb, B_WR);
- return -1;
- }
- fb->bytes_sent += i;
- if (fb->flags & B_EOUT)
- return -1;
- else
- return i;
+ return bcwrite(fb, buf, nbyte);
}
#ifndef NO_WRITEV
@@ -1010,9 +1035,6 @@
}
#endif
- /* in case a chunk hasn't been started yet */
- if( fb->flags & B_CHUNK ) start_chunk( fb );
-
/*
* Whilst there is data in the buffer, keep on adding to it and writing it
* out
@@ -1041,25 +1063,15 @@
*/
if (write_it_all(fb, fb->outbase, fb->outcnt) == -1) {
/* we cannot continue after a chunked error */
- doerror (fb, B_WR);
return -1;
}
fb->outcnt = 0;
break;
}
- do {
- i = buff_write(fb, fb->outbase, fb->outcnt);
- } while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+ i = write_with_errors (fb, fb->outbase, fb->outcnt);
if (i <= 0) {
- if (i == 0) /* return of 0 means non-blocking */
- errno = EAGAIN;
- if (nwr == 0) {
- if (errno != EAGAIN) doerror(fb, B_WR);
- return -1;
- }
- else return nwr;
+ return nwr ? nwr : -1;
}
- fb->bytes_sent += i;
/* deal with a partial write */
if (i < fb->outcnt)
@@ -1082,18 +1094,10 @@
*/
while (nbyte >= fb->bufsiz)
{
- do i = bcwrite(fb, buf, nbyte);
- while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+ i = bcwrite(fb, buf, nbyte);
if (i <= 0) {
- if (i == 0) /* return of 0 means non-blocking */
- errno = EAGAIN;
- if (nwr == 0) {
- if (errno != EAGAIN) doerror(fb, B_WR);
- return -1;
- }
- else return nwr;
+ return nwr ? nwr : -1;
}
- fb->bytes_sent += i;
buf = i + (const char *)buf;
nwr += i;
@@ -1127,18 +1131,8 @@
while (fb->outcnt > 0)
{
- do {
- i = buff_write(fb, fb->outbase, fb->outcnt);
- } while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
- if (i == 0) {
- errno = EAGAIN;
- return -1; /* return of 0 means non-blocking */
- }
- else if (i < 0) {
- if (errno != EAGAIN) doerror(fb, B_WR);
- return -1;
- }
- fb->bytes_sent += i;
+ i = write_with_errors (fb, fb->outbase, fb->outcnt);
+ if (i <= 0) return -1;
/*
* We should have written all the data, but if the fd was in a
@@ -1158,6 +1152,7 @@
if (fb->flags & B_EOUT)
return -1;
}
+
return 0;
}
Index: buff.h
===================================================================
RCS file: /export/home/cvs/apache/src/buff.h,v
retrieving revision 1.22
diff -u -r1.22 buff.h
--- buff.h 1997/07/24 04:23:57 1.22
+++ buff.h 1997/08/08 07:54:46
@@ -167,3 +167,6 @@
API_EXPORT(int) bnonblock(BUFF *fb, int direction);
/* and get an fd to select() on */
API_EXPORT(int) bfileno(BUFF *fb, int direction);
+
+/* bflush() if a read now would block, but don't actually read anything */
+API_EXPORT(void) bhalfduplex (BUFF *fb);
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.c,v
retrieving revision 1.197
diff -u -r1.197 http_main.c
--- http_main.c 1997/08/05 06:02:41 1.197
+++ http_main.c 1997/08/08 07:54:54
@@ -2398,7 +2398,7 @@
if (lr == NULL) continue;
sd = lr->fd;
} else {
- /* there's only one socket, just pretend we the other stuff */
+ /* only one socket, just pretend we did the other stuff */
sd = listeners->fd;
}
Index: http_request.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_request.c,v
retrieving revision 1.72
diff -u -r1.72 http_request.c
--- http_request.c 1997/08/07 08:15:29 1.72
+++ http_request.c 1997/08/08 07:54:56
@@ -411,7 +411,7 @@
void *htaccess_conf = NULL;
res = parse_htaccess (&htaccess_conf, r, overrides_here,
- test_dirname, sconf->access_name);
+ pstrdup (r->pool, test_dirname),
sconf->access_name);
if (res) return res;
if (htaccess_conf)
@@ -1076,6 +1076,14 @@
old_stat = update_child_status (r->connection->child_num, SERVER_BUSY_LOG,
r);
#endif /* STATUS */
+
+ /* We want to flush the last packet if this isn't a pipelining
+ * connection *before* we start into logging. Suppose that the logging
+ * causes a DNS lookup to occur, which may have a high latency. If
+ * we hold off on this packet, then it'll appear like the link is
+ * stalled when really it's the application that's stalled.
+ */
+ bhalfduplex (r->connection->client);
log_transaction (r);
#ifdef STATUS
(void)update_child_status (r->connection->child_num, old_stat, r);