What is the semantic of runtime.netpollWaiters?
If it should track number of goroutines waiting for poll result, then it is implemented incorrectly (at least on Linux with epoll).
I see that runtime.netpollWaiters is incremented every time new goroutine getting blocked on polling:
Apparently atomic.Load(&netpollWaiters) > 0 condition in the referenced above runtime.findrunnable() and runtime.pollWork() functions is always true, as soon as as single goroutine will wait for poll result and get awakened from those functions.
I verified that runtime.netpollWaiters is increased with each wait of a goroutine on network in an example of handling TCP conection:
$ dlv debug tcp-socket.go
Type 'help' for list of commands.
(dlv) p runtime.netpollWaiters
0
(dlv) c
Launching server...
received SIGINT, stopping process (will not forward signal)
> runtime.epollwait() /usr/lib/golang/src/runtime/sys_linux_amd64.s:675 (PC: 0x4619e0)
Warning: debugging optimized function
(dlv) p runtime.netpollWaiters
1
(dlv) c
Message Received:message 1 from netcat
Message Received:message 2 from netcat
received SIGINT, stopping process (will not forward signal)
> runtime.epollwait() /usr/lib/golang/src/runtime/sys_linux_amd64.s:675 (PC: 0x4619e0)
Warning: debugging optimized function
(dlv) p runtime.netpollWaiters
4
(dlv)
What is the semantic of runtime.netpollWaiters? If it should track number of goroutines waiting for poll result, then it is implemented incorrectly (at least on Linux with epoll).
I see that runtime.netpollWaiters is incremented every time new goroutine getting blocked on polling:
https://github.com/golang/go/blob/f686a2890b34996455c7d7aba9a0efba74b613f5/src/runtime/netpoll.go#L354-L363
and decremented only in
func netpollgoready(gp *g, traceskip int)
:https://github.com/golang/go/blob/f686a2890b34996455c7d7aba9a0efba74b613f5/src/runtime/netpoll.go#L365-L368
Looks like
netpollgoready()
is called only frominternal/poll.runtime_pollSetDeadline()
, i.e. in some codepaths related to setting polling deadlines:https://github.com/golang/go/blob/f686a2890b34996455c7d7aba9a0efba74b613f5/src/runtime/netpoll.go#L204-L205
And most frequently parked goroutine waiting for poll result is being awakened somewhere in
runtime.findrunnable()
:https://github.com/golang/go/blob/61bb56ad63992a3199acc55b2537c8355ef887b6/src/runtime/proc.go#L2210-L2221
or
runtime.pollWork()
:https://github.com/golang/go/blob/61bb56ad63992a3199acc55b2537c8355ef887b6/src/runtime/proc.go#L2395-L2409
Apparently
atomic.Load(&netpollWaiters) > 0
condition in the referenced aboveruntime.findrunnable()
andruntime.pollWork()
functions is always true, as soon as as single goroutine will wait for poll result and get awakened from those functions.I verified that
runtime.netpollWaiters
is increased with each wait of a goroutine on network in an example of handling TCP conection:Snippet from
go env
: