Fixes listen/TCP bug
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 1 Apr 2014 00:15:33 +0000 (17:15 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 1 Apr 2014 00:15:33 +0000 (17:15 -0700)
Listeners wouldn't wake, at least for TCP, when the connection hung up.

kern/src/net/devip.c
kern/src/net/tcp.c

index 473cecd..ab78a0d 100644 (file)
@@ -351,12 +351,13 @@ static int ipstat(struct chan *c, uint8_t * db, int n)
        return devstat(c, db, n, NULL, 0, ipgen);
 }
 
-static int incoming(void *arg)
+static int should_wake(void *arg)
 {
-       struct conv *conv;
-
-       conv = arg;
-       return conv->incall != NULL;
+       struct conv *cv = arg;
+       /* signal that the conv is closed */
+       if (qisclosed(cv->rq))
+               return TRUE;
+       return cv->incall != NULL;
 }
 
 static int m2p[] = {
@@ -493,8 +494,10 @@ static struct chan *ipopen(struct chan *c, int omode)
                                }
 
                                /* wait for a connect */
-                               rendez_sleep(&cv->listenr, incoming, cv);
+                               rendez_sleep(&cv->listenr, should_wake, cv);
 
+                               /* if there is a concurrent hangup, they will hold the qlock
+                                * until the hangup is complete, including closing the cv->rq */
                                qlock(&cv->qlock);
                                nc = cv->incall;
                                if (nc != NULL) {
index 534250c..3457d85 100644 (file)
@@ -736,13 +736,15 @@ void localclose(struct conv *s, char *reason)
 
        if (tcb->state == Syn_sent)
                Fsconnected(s, reason);
-       if (s->state == Announced)
-               rendez_wakeup(&s->listenr);
 
        qhangup(s->rq, reason);
        qhangup(s->wq, reason);
 
        tcpsetstate(s, Closed);
+
+       /* listener will check the rq state */
+       if (s->state == Announced)
+               rendez_wakeup(&s->listenr);
 }
 
 /* mtu (- TCP + IP hdr len) of 1st hop */