]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix network timers related crash
authorDmitriy Vyukov <dvyukov@google.com>
Tue, 13 Aug 2013 08:55:57 +0000 (12:55 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Tue, 13 Aug 2013 08:55:57 +0000 (12:55 +0400)
Fixes #6103.

R=golang-dev, alex.brainman
CC=golang-dev
https://golang.org/cl/12686045

src/pkg/net/timeout_test.go
src/pkg/runtime/netpoll.goc

index 2e92147b8e33e923390f92c9701a815d241b37dc..76f51b38a5c1cacd134637eb30974464d51b75b0 100644 (file)
@@ -703,3 +703,36 @@ func TestProlongTimeout(t *testing.T) {
                c.Write(buf[:])
        }
 }
+
+func TestDeadlineRace(t *testing.T) {
+       switch runtime.GOOS {
+       case "plan9":
+               t.Skipf("skipping test on %q", runtime.GOOS)
+       }
+
+       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+       ln := newLocalListener(t)
+       defer ln.Close()
+       c, err := Dial("tcp", ln.Addr().String())
+       if err != nil {
+               t.Fatalf("Dial: %v", err)
+       }
+       defer c.Close()
+       done := make(chan bool)
+       go func() {
+               t := time.NewTicker(2 * time.Microsecond).C
+               for {
+                       if err := c.SetDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
+                               break
+                       }
+                       <-t
+               }
+               done <- true
+       }()
+       var buf [1]byte
+       for i := 0; i < 1024; i++ {
+               c.Read(buf[:]) // ignore possible timeout errors
+       }
+       c.Close()
+       <-done
+}
index ebe6defa00b9761ea3b597d204b925aed10bc0c3..da6929eed2e52ad21eb74be5bd57d56a641ecd7c 100644 (file)
@@ -113,10 +113,13 @@ func runtime_pollWait(pd *PollDesc, mode int) (err int) {
        runtime·lock(pd);
        err = checkerr(pd, mode);
        if(err == 0) {
-               if(!netpollblock(pd, mode)) {
+               while(!netpollblock(pd, mode)) {
                        err = checkerr(pd, mode);
-                       if(err == 0)
-                               runtime·throw("runtime_pollWait: unblocked by ioready");
+                       if(err != 0)
+                               break;
+                       // Can happen if timeout has fired and unblocked us,
+                       // but before we had a chance to run, timeout has been reset.
+                       // Pretend it has not happened and retry.
                }
        }
        runtime·unlock(pd);