ipv6: shut down the PacketConn on failure in TestPacketConnConcurrentReadWriteUnicast

This avoids a deadlock (observed in golang/go#50455) that may
otherwise swallow the error logs from a failure, which may help us
better diagnose the underlying problem.

For golang/go#50455.

Change-Id: Id73bd9589ae23385a433da0b24840ef945601f63
Reviewed-on: https://go-review.googlesource.com/c/net/+/376094
Trust: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/ipv6/readwrite_test.go b/ipv6/readwrite_test.go
index 260e7ee..9d1ed88 100644
--- a/ipv6/readwrite_test.go
+++ b/ipv6/readwrite_test.go
@@ -356,8 +356,6 @@
 }
 
 func testPacketConnConcurrentReadWriteUnicast(t *testing.T, p *ipv6.PacketConn, data []byte, dst net.Addr, batch bool) {
-	t.Helper()
-
 	ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
 	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
 
@@ -368,23 +366,37 @@
 		t.Fatal(err)
 	}
 
+	var firstError sync.Once
+	fatalf := func(format string, args ...interface{}) {
+		// On the first error, close the PacketConn to unblock the remaining
+		// goroutines. Suppress any further errors, which may occur simply due to
+		// closing the PacketConn.
+		first := false
+		firstError.Do(func() {
+			first = true
+			p.Close()
+		})
+		if first {
+			t.Helper()
+			t.Errorf(format, args...)
+		}
+		runtime.Goexit()
+	}
+
 	var wg sync.WaitGroup
 	reader := func() {
 		defer wg.Done()
 		b := make([]byte, 128)
 		n, cm, _, err := p.ReadFrom(b)
 		if err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
 		if !bytes.Equal(b[:n], data) {
-			t.Errorf("got %#v; want %#v", b[:n], data)
-			return
+			fatalf("got %#v; want %#v", b[:n], data)
 		}
 		s := cm.String()
 		if strings.Contains(s, ",") {
-			t.Errorf("should be space-separated values: %s", s)
-			return
+			fatalf("should be space-separated values: %s", s)
 		}
 	}
 	batchReader := func() {
@@ -397,27 +409,22 @@
 		}
 		n, err := p.ReadBatch(ms, 0)
 		if err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
 		if n != len(ms) {
-			t.Errorf("got %d; want %d", n, len(ms))
-			return
+			fatalf("got %d; want %d", n, len(ms))
 		}
 		var cm ipv6.ControlMessage
 		if err := cm.Parse(ms[0].OOB[:ms[0].NN]); err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
 		b := ms[0].Buffers[0][:ms[0].N]
 		if !bytes.Equal(b, data) {
-			t.Errorf("got %#v; want %#v", b, data)
-			return
+			fatalf("got %#v; want %#v", b, data)
 		}
 		s := cm.String()
 		if strings.Contains(s, ",") {
-			t.Errorf("should be space-separated values: %s", s)
-			return
+			fatalf("should be space-separated values: %s", s)
 		}
 	}
 	writer := func(toggle bool) {
@@ -431,17 +438,14 @@
 			cm.IfIndex = ifi.Index
 		}
 		if err := p.SetControlMessage(cf, toggle); err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
 		n, err := p.WriteTo(data, &cm, dst)
 		if err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
 		if n != len(data) {
-			t.Errorf("got %d; want %d", n, len(data))
-			return
+			fatalf("got %d; want %d", n, len(data))
 		}
 	}
 	batchWriter := func(toggle bool) {
@@ -455,8 +459,7 @@
 			cm.IfIndex = ifi.Index
 		}
 		if err := p.SetControlMessage(cf, toggle); err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
 		ms := []ipv6.Message{
 			{
@@ -467,16 +470,13 @@
 		}
 		n, err := p.WriteBatch(ms, 0)
 		if err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
 		if n != len(ms) {
-			t.Errorf("got %d; want %d", n, len(ms))
-			return
+			fatalf("got %d; want %d", n, len(ms))
 		}
 		if ms[0].N != len(data) {
-			t.Errorf("got %d; want %d", ms[0].N, len(data))
-			return
+			fatalf("got %d; want %d", ms[0].N, len(data))
 		}
 	}