Skip to content

Commit eaa8419

Browse files
ianlancetaylorgopherbot
authored andcommitted
runtime: decrement netpollWaiters in netpollunblock
We used to decrement it in netpollgoready, but that missed the common case of a descriptor becoming ready due to I/O. All calls to netpollgoready go through netpollunblock, so this shouldn't miss any decrements we missed before. Fixes #60782 Change-Id: Ideefefa1ac96ca38e09fe2dd5d595c5dd7883237 Reviewed-on: https://go-review.googlesource.com/c/go/+/503923 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]>
1 parent 21ff9be commit eaa8419

File tree

3 files changed

+80
-2
lines changed

3 files changed

+80
-2
lines changed

src/runtime/crash_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,3 +869,12 @@ func TestPanicOnUnsafeSlice(t *testing.T) {
869869
t.Errorf("output does not contain %q:\n%s", want, output)
870870
}
871871
}
872+
873+
func TestNetpollWaiters(t *testing.T) {
874+
t.Parallel()
875+
output := runTestProg(t, "testprognet", "NetpollWaiters")
876+
want := "OK\n"
877+
if output != want {
878+
t.Fatalf("output is not %q\n%s", want, output)
879+
}
880+
}

src/runtime/netpoll.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,6 @@ func netpollblockcommit(gp *g, gpp unsafe.Pointer) bool {
526526
}
527527

528528
func netpollgoready(gp *g, traceskip int) {
529-
netpollWaiters.Add(-1)
530529
goready(gp, traceskip+1)
531530
}
532531

@@ -587,13 +586,15 @@ func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g {
587586
// will check for timeout/cancel before waiting.
588587
return nil
589588
}
590-
var new uintptr
589+
new := pdNil
591590
if ioready {
592591
new = pdReady
593592
}
594593
if gpp.CompareAndSwap(old, new) {
595594
if old == pdWait {
596595
old = pdNil
596+
} else if old != pdNil {
597+
netpollWaiters.Add(-1)
597598
}
598599
return (*g)(unsafe.Pointer(old))
599600
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"fmt"
9+
"io"
10+
"log"
11+
"net"
12+
"runtime/internal/atomic"
13+
"sync"
14+
"time"
15+
_ "unsafe" // for go:linkname
16+
)
17+
18+
// The bug is that netpollWaiters increases monotonically.
19+
// This doesn't cause a problem until it overflows.
20+
// Use linkname to see the value.
21+
//go:linkname netpollWaiters runtime.netpollWaiters
22+
var netpollWaiters atomic.Uint32
23+
24+
func init() {
25+
register("NetpollWaiters", NetpollWaiters)
26+
}
27+
28+
func NetpollWaiters() {
29+
listener, err := net.Listen("tcp", "127.0.0.1:0")
30+
if err != nil {
31+
log.Fatal(err)
32+
}
33+
34+
var wg sync.WaitGroup
35+
wg.Add(1)
36+
go func() {
37+
defer wg.Done()
38+
conn, err := listener.Accept()
39+
if err != nil {
40+
log.Fatal(err)
41+
}
42+
defer conn.Close()
43+
if _, err := io.Copy(io.Discard, conn); err != nil {
44+
log.Fatal(err)
45+
}
46+
}()
47+
48+
wg.Add(1)
49+
go func() {
50+
defer wg.Done()
51+
conn, err := net.Dial("tcp", listener.Addr().String())
52+
if err != nil {
53+
log.Fatal(err)
54+
}
55+
defer conn.Close()
56+
for i := 0; i < 10; i++ {
57+
fmt.Fprintf(conn, "%d\n", i)
58+
time.Sleep(time.Millisecond)
59+
}
60+
}()
61+
62+
wg.Wait()
63+
if v := netpollWaiters.Load(); v != 0 {
64+
log.Fatalf("current waiters %v", v)
65+
}
66+
67+
fmt.Println("OK")
68+
}

0 commit comments

Comments
 (0)