]> Cypherpunks repositories - gostls13.git/commitdiff
net: fix concurrent Accept on windows
authorDmitriy Vyukov <dvyukov@google.com>
Sun, 4 Aug 2013 19:31:23 +0000 (23:31 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Sun, 4 Aug 2013 19:31:23 +0000 (23:31 +0400)
Runtime netpoll supports at most one read waiter
and at most one write waiter. It's responsibility
of net package to ensure that. Currently windows
implementation allows more than one waiter in Accept.
It leads to "fatal error: netpollblock: double wait".

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12400045

src/pkg/net/fd_windows.go
src/pkg/net/tcp_test.go

index 5d584621a7142d3a00cd28d7992b5400a1270090..f51d1616e0154234c93550be0eb72761a8cc3f30 100644 (file)
@@ -579,6 +579,8 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
        }
 
        // Submit accept request.
+       fd.rio.Lock()
+       defer fd.rio.Unlock()
        var o acceptOp
        o.Init(fd, 'r')
        o.newsock = s
index a71b02b47747a40d63d4ed947130b04d0ac4ce08..f356f92f0967afd6ec1855dbc0fc8bfa7747f85f 100644 (file)
@@ -8,6 +8,7 @@ import (
        "fmt"
        "reflect"
        "runtime"
+       "sync"
        "testing"
        "time"
 )
@@ -294,3 +295,35 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
                <-done
        }
 }
+
+func TestTCPConcurrentAccept(t *testing.T) {
+       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+       ln, err := Listen("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatalf("Listen failed: %v", err)
+       }
+       const N = 10
+       var wg sync.WaitGroup
+       wg.Add(N)
+       for i := 0; i < N; i++ {
+               go func() {
+                       for {
+                               c, err := ln.Accept()
+                               if err != nil {
+                                       break
+                               }
+                               c.Close()
+                       }
+                       wg.Done()
+               }()
+       }
+       for i := 0; i < 10*N; i++ {
+               c, err := Dial("tcp", ln.Addr().String())
+               if err != nil {
+                       t.Fatalf("Dial failed: %v", err)
+               }
+               c.Close()
+       }
+       ln.Close()
+       wg.Wait()
+}