shithub: 9pro

Download patch

ref: 290a0bec7f7c1328a98ac7a367de62f8d5d6b2b7
parent: 1bfefe551389909d88c22c51f3c33a524cebf827
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Mon Dec 23 07:44:19 EST 2019

process all the incoming data first, then send out the responses

--- a/9pex.c
+++ b/9pex.c
@@ -93,7 +93,7 @@
 static C9qid walkqids[C9maxpathel];
 static uint8_t *rdbuf;
 static uint8_t *wrbuf;
-static int wroff;
+static uint32_t wroff, wrend, wrbufsz;
 
 __attribute__ ((format (printf, 1, 2)))
 static void
@@ -110,7 +110,7 @@
 }
 
 static int
-canrw(int rdonly)
+canrw(int rdonly, int block)
 {
 	struct timeval t;
 	fd_set r, w, e;
@@ -118,16 +118,15 @@
 
 	FD_ZERO(&r);
 	FD_SET(in, &r);
-	if (rdonly == 0) {
-		FD_ZERO(&w);
+	FD_ZERO(&w);
+	if (rdonly == 0)
 		FD_SET(out, &w);
-	}
 	FD_ZERO(&e);
 	FD_SET(in, &e);
 	FD_SET(out, &e);
 	memset(&t, 0, sizeof(t));
 	t.tv_usec = 1000;
-	if ((n = select(max(in, out) + 1, &r, &w, &e, rdonly ? NULL : &t)) < 0 || FD_ISSET(in, &e) || FD_ISSET(out, &e))
+	if ((n = select(max(in, out) + 1, &r, &w, &e, block ? NULL : &t)) < 0 || FD_ISSET(in, &e) || FD_ISSET(out, &e))
 		return -1;
 
 	fl = 0;
@@ -140,6 +139,21 @@
 }
 
 static int
+wrsend(void)
+{
+	if (wrend == 0)
+		return 0;
+	if (write(out, wrbuf, wrend) != wrend) {
+		perror("write");
+		return -1;
+	}
+	memmove(wrbuf, wrbuf+wrend, wroff-wrend);
+	wroff = wroff - wrend;
+
+	return 0;
+}
+
+static int
 hastag(C9tag tag)
 {
 	int i;
@@ -473,6 +487,10 @@
 	uint8_t *b;
 
 	used(c);
+	if (wroff + size > wrbufsz) {
+		if (wrsend() != 0 || wroff + size > wrbufsz)
+			return NULL;
+	}
 	b = wrbuf + wroff;
 	wroff += size;
 
@@ -483,11 +501,7 @@
 ctxend(C9ctx *c)
 {
 	used(c);
-
-	if (write(out, wrbuf, wroff) != wroff)
-		return -1;
-	wroff = 0;
-
+	wrend = wroff;
 	return 0;
 }
 
@@ -716,7 +730,7 @@
 	char *err;
 	Fid *f;
 	struct parg_state ps;
-	int can, i, c;
+	int can, i, c, rdonly, block;
 
 	parg_init(&ps);
 
@@ -777,15 +791,32 @@
 	ctx.error = ctxerror;
 
 	rdbuf = calloc(1, ctx.msize);
-	wrbuf = calloc(1, ctx.msize);
-	wroff = 0;
+	wrbufsz = ctx.msize;
+	wrbuf = calloc(1, wrbufsz);
+	wroff = wrend = 0;
 
 	err = NULL;
+	rdonly = block = 1; /* at first we wait until the client sends in data */
 	for (; !eof;) {
-		if ((can = canrw(1)) < 0)
+		if ((can = canrw(rdonly, block)) < 0)
 			break;
-		if ((can & Canrd) != 0 && s9do(s9proc(&ctx), &err) != 0)
-			break;
+		if ((can & Canrd) != 0) { /* if there is data, process it */
+			if (s9do(s9proc(&ctx), &err) != 0)
+				break;
+			/* give it a chance to receive all the data first */
+			rdonly = 1;
+			block = 0;
+		} else if (block == 0) { /* got all the data */
+			if (rdonly != 0) { /* wait until we can send OR we get more data */
+				rdonly = 0;
+				block = 1;
+			}
+		} else if (rdonly == 0 && (can & Canwr) != 0) { /* can send */
+			if (wrsend() != 0) /* send all the data */
+				break;
+			rdonly = 1; /* and go back to reading */
+			block = 1;
+		}
 	}
 
 	if (err != NULL)