Commit de990545 authored by Austin Clements's avatar Austin Clements

runtime: use gList in netpoll

netpoll is perhaps one of the most confusing uses of G lists currently
since it passes around many lists as bare *g values right now.
Switching to gList makes it much clearer what's an individual g and
what's a list.

Change-Id: I8d8993c4967c5bae049c7a094aad3a657928ba6c
Reviewed-on: https://go-review.googlesource.com/129397
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarRick Hudson <rlh@golang.org>
parent 3578918b
......@@ -289,24 +289,22 @@ func poll_runtime_pollUnblock(pd *pollDesc) {
}
}
// make pd ready, newly runnable goroutines (if any) are returned in rg/wg
// make pd ready, newly runnable goroutines (if any) are added to toRun.
// May run during STW, so write barriers are not allowed.
//go:nowritebarrier
func netpollready(gpp *guintptr, pd *pollDesc, mode int32) {
var rg, wg guintptr
func netpollready(toRun *gList, pd *pollDesc, mode int32) {
var rg, wg *g
if mode == 'r' || mode == 'r'+'w' {
rg.set(netpollunblock(pd, 'r', true))
rg = netpollunblock(pd, 'r', true)
}
if mode == 'w' || mode == 'r'+'w' {
wg.set(netpollunblock(pd, 'w', true))
wg = netpollunblock(pd, 'w', true)
}
if rg != 0 {
rg.ptr().schedlink = *gpp
*gpp = rg
if rg != nil {
toRun.push(rg)
}
if wg != 0 {
wg.ptr().schedlink = *gpp
*gpp = wg
if wg != nil {
toRun.push(wg)
}
}
......
......@@ -58,9 +58,9 @@ func netpollarm(pd *pollDesc, mode int) {
// polls for ready network connections
// returns list of goroutines that become runnable
func netpoll(block bool) *g {
func netpoll(block bool) gList {
if epfd == -1 {
return nil
return gList{}
}
waitms := int32(-1)
if !block {
......@@ -76,7 +76,7 @@ retry:
}
goto retry
}
var gp guintptr
var toRun gList
for i := int32(0); i < n; i++ {
ev := &events[i]
if ev.events == 0 {
......@@ -92,11 +92,11 @@ retry:
if mode != 0 {
pd := *(**pollDesc)(unsafe.Pointer(&ev.data))
netpollready(&gp, pd, mode)
netpollready(&toRun, pd, mode)
}
}
if block && gp == 0 {
if block && toRun.empty() {
goto retry
}
return gp.ptr()
return toRun
}
......@@ -27,6 +27,6 @@ func netpollclose(fd uintptr) int32 {
func netpollarm(pd *pollDesc, mode int) {
}
func netpoll(block bool) *g {
return nil
func netpoll(block bool) gList {
return gList{}
}
......@@ -59,9 +59,9 @@ func netpollarm(pd *pollDesc, mode int) {
// Polls for ready network connections.
// Returns list of goroutines that become runnable.
func netpoll(block bool) *g {
func netpoll(block bool) gList {
if kq == -1 {
return nil
return gList{}
}
var tp *timespec
var ts timespec
......@@ -78,7 +78,7 @@ retry:
}
goto retry
}
var gp guintptr
var toRun gList
for i := 0; i < int(n); i++ {
ev := &events[i]
var mode int32
......@@ -102,11 +102,11 @@ retry:
mode += 'w'
}
if mode != 0 {
netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
netpollready(&toRun, (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
}
}
if block && gp == 0 {
if block && toRun.empty() {
goto retry
}
return gp.ptr()
return toRun
}
......@@ -180,9 +180,9 @@ func netpollarm(pd *pollDesc, mode int) {
// polls for ready network connections
// returns list of goroutines that become runnable
func netpoll(block bool) *g {
func netpoll(block bool) gList {
if portfd == -1 {
return nil
return gList{}
}
var wait *timespec
......@@ -202,7 +202,7 @@ retry:
goto retry
}
var gp guintptr
var toRun gList
for i := 0; i < int(n); i++ {
ev := &events[i]
......@@ -233,12 +233,12 @@ retry:
}
if mode != 0 {
netpollready(&gp, pd, mode)
netpollready(&toRun, pd, mode)
}
}
if block && gp == 0 {
if block && toRun.empty() {
goto retry
}
return gp.ptr()
return toRun
}
......@@ -10,10 +10,10 @@ var netpollWaiters uint32
// Polls for ready network connections.
// Returns list of goroutines that become runnable.
func netpoll(block bool) (gp *g) {
func netpoll(block bool) gList {
// Implementation for platforms that do not support
// integrated network poller.
return
return gList{}
}
func netpollinited() bool {
......
......@@ -63,17 +63,17 @@ func netpollarm(pd *pollDesc, mode int) {
// Polls for completed network IO.
// Returns list of goroutines that become runnable.
func netpoll(block bool) *g {
func netpoll(block bool) gList {
var entries [64]overlappedEntry
var wait, qty, key, flags, n, i uint32
var errno int32
var op *net_op
var gp guintptr
var toRun gList
mp := getg().m
if iocphandle == _INVALID_HANDLE_VALUE {
return nil
return gList{}
}
wait = 0
if block {
......@@ -92,7 +92,7 @@ retry:
mp.blocked = false
errno = int32(getlasterror())
if !block && errno == _WAIT_TIMEOUT {
return nil
return gList{}
}
println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
throw("runtime: netpoll failed")
......@@ -105,7 +105,7 @@ retry:
if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
errno = int32(getlasterror())
}
handlecompletion(&gp, op, errno, qty)
handlecompletion(&toRun, op, errno, qty)
}
} else {
op = nil
......@@ -118,7 +118,7 @@ retry:
mp.blocked = false
errno = int32(getlasterror())
if !block && errno == _WAIT_TIMEOUT {
return nil
return gList{}
}
if op == nil {
println("runtime: GetQueuedCompletionStatus failed (errno=", errno, ")")
......@@ -127,15 +127,15 @@ retry:
// dequeued failed IO packet, so report that
}
mp.blocked = false
handlecompletion(&gp, op, errno, qty)
handlecompletion(&toRun, op, errno, qty)
}
if block && gp == 0 {
if block && toRun.empty() {
goto retry
}
return gp.ptr()
return toRun
}
func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
func handlecompletion(toRun *gList, op *net_op, errno int32, qty uint32) {
if op == nil {
println("runtime: GetQueuedCompletionStatus returned op == nil")
throw("runtime: netpoll failed")
......@@ -147,5 +147,5 @@ func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
}
op.errno = errno
op.qty = qty
netpollready(gpp, op.pd, mode)
netpollready(toRun, op.pd, mode)
}
......@@ -1148,8 +1148,8 @@ func startTheWorldWithSema(emitTraceEvent bool) int64 {
_g_.m.locks++ // disable preemption because it can be holding p in a local var
if netpollinited() {
gp := netpoll(false) // non-blocking
injectglist(gp)
list := netpoll(false) // non-blocking
injectglist(list.head.ptr())
}
add := needaddgcproc()
lock(&sched.lock)
......@@ -2312,9 +2312,9 @@ top:
// not set lastpoll yet), this thread will do blocking netpoll below
// anyway.
if netpollinited() && atomic.Load(&netpollWaiters) > 0 && atomic.Load64(&sched.lastpoll) != 0 {
if gp := netpoll(false); gp != nil { // non-blocking
// netpoll returns list of goroutines linked by schedlink.
injectglist(gp.schedlink.ptr())
if list := netpoll(false); !list.empty() { // non-blocking
gp := list.pop()
injectglist(list.head.ptr())
casgstatus(gp, _Gwaiting, _Grunnable)
if trace.enabled {
traceGoUnpark(gp, 0)
......@@ -2466,22 +2466,23 @@ stop:
if _g_.m.spinning {
throw("findrunnable: netpoll with spinning")
}
gp := netpoll(true) // block until new work is available
list := netpoll(true) // block until new work is available
atomic.Store64(&sched.lastpoll, uint64(nanotime()))
if gp != nil {
if !list.empty() {
lock(&sched.lock)
_p_ = pidleget()
unlock(&sched.lock)
if _p_ != nil {
acquirep(_p_)
injectglist(gp.schedlink.ptr())
gp := list.pop()
injectglist(list.head.ptr())
casgstatus(gp, _Gwaiting, _Grunnable)
if trace.enabled {
traceGoUnpark(gp, 0)
}
return gp, false
}
injectglist(gp)
injectglist(list.head.ptr())
}
}
stopm()
......@@ -2501,8 +2502,8 @@ func pollWork() bool {
return true
}
if netpollinited() && atomic.Load(&netpollWaiters) > 0 && sched.lastpoll != 0 {
if gp := netpoll(false); gp != nil {
injectglist(gp)
if list := netpoll(false); !list.empty() {
injectglist(list.head.ptr())
return true
}
}
......@@ -4387,8 +4388,8 @@ func sysmon() {
now := nanotime()
if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now {
atomic.Cas64(&sched.lastpoll, uint64(lastpoll), uint64(now))
gp := netpoll(false) // non-blocking - returns list of goroutines
if gp != nil {
list := netpoll(false) // non-blocking - returns list of goroutines
if !list.empty() {
// Need to decrement number of idle locked M's
// (pretending that one more is running) before injectglist.
// Otherwise it can lead to the following situation:
......@@ -4397,7 +4398,7 @@ func sysmon() {
// observes that there is no work to do and no other running M's
// and reports deadlock.
incidlelocked(-1)
injectglist(gp)
injectglist(list.head.ptr())
incidlelocked(1)
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment