Source File
netpoll.go
Belonging Package
runtime
package runtime
import (
)
const (
pollNoError = 0 // no error
pollErrClosing = 1 // descriptor is closed
pollErrTimeout = 2 // I/O timeout
pollErrNotPollable = 3 // general error polling descriptor
)
const (
pdReady uintptr = 1
pdWait uintptr = 2
)
const pollBlockSize = 4 * 1024
lock mutex // protects the following fields
fd uintptr
closing bool
everr bool // marks event scanning error happened
user uint32 // user settable cookie
rseq uintptr // protects from stale read timers
rg uintptr // pdReady, pdWait, G waiting for read or nil
rt timer // read deadline timer (set if rt.f != nil)
rd int64 // read deadline
wseq uintptr // protects from stale write timers
wg uintptr // pdReady, pdWait, G waiting for write or nil
wt timer // write deadline timer
wd int64 // write deadline
self *pollDesc // storage for indirect interface. See (*pollDesc).makeArg.
}
type pollCache struct {
lock mutex
func () {
netpollGenericInit()
}
func () {
if atomic.Load(&netpollInited) == 0 {
lockInit(&netpollInitLock, lockRankNetpollInit)
lock(&netpollInitLock)
if netpollInited == 0 {
netpollinit()
atomic.Store(&netpollInited, 1)
}
unlock(&netpollInitLock)
}
}
func () bool {
return atomic.Load(&netpollInited) != 0
}
func ( uintptr) bool {
return netpollIsPollDescriptor()
}
func ( uintptr) (*pollDesc, int) {
:= pollcache.alloc()
lock(&.lock)
if .wg != 0 && .wg != pdReady {
throw("runtime: blocked write on free polldesc")
}
if .rg != 0 && .rg != pdReady {
throw("runtime: blocked read on free polldesc")
}
.fd =
.closing = false
.everr = false
.rseq++
.rg = 0
.rd = 0
.wseq++
.wg = 0
.wd = 0
.self =
unlock(&.lock)
var int32
= netpollopen(, )
return , int()
}
func ( *pollDesc) {
if !.closing {
throw("runtime: close polldesc w/o unblock")
}
if .wg != 0 && .wg != pdReady {
throw("runtime: blocked write on closing polldesc")
}
if .rg != 0 && .rg != pdReady {
throw("runtime: blocked read on closing polldesc")
}
netpollclose(.fd)
pollcache.free()
}
func ( *pollCache) ( *pollDesc) {
lock(&.lock)
.link = .first
.first =
unlock(&.lock)
}
func ( *pollDesc, int) int {
:= netpollcheckerr(, int32())
if != pollNoError {
return
}
if == 'r' {
.rg = 0
} else if == 'w' {
.wg = 0
}
return pollNoError
}
func ( *pollDesc, int) int {
:= netpollcheckerr(, int32())
if != pollNoError {
return
if GOOS == "solaris" || GOOS == "illumos" || GOOS == "aix" {
netpollarm(, )
}
for !netpollblock(, int32(), false) {
= netpollcheckerr(, int32())
if != pollNoError {
return
}
return pollNoError
}
for !netpollblock(, int32(), true) {
}
}
.rt.arg = .makeArg()
.rt.seq = .rseq
resettimer(&.rt, .rd)
}
} else if .rd != || != {
.rseq++ // invalidate current timers
if .rd > 0 {
modtimer(&.rt, .rd, 0, , .makeArg(), .rseq)
} else {
deltimer(&.rt)
.rt.f = nil
}
}
if .wt.f == nil {
if .wd > 0 && ! {
.wt.f = netpollWriteDeadline
.wt.arg = .makeArg()
.wt.seq = .wseq
resettimer(&.wt, .wd)
}
} else if .wd != || != {
.wseq++ // invalidate current timers
if .wd > 0 && ! {
modtimer(&.wt, .wd, 0, netpollWriteDeadline, .makeArg(), .wseq)
} else {
deltimer(&.wt)
.wt.f = nil
}
var , *g
if .rd < 0 || .wd < 0 {
atomic.StorepNoWB(noescape(unsafe.Pointer(&)), nil) // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
if .rd < 0 {
= netpollunblock(, 'r', false)
}
if .wd < 0 {
= netpollunblock(, 'w', false)
}
}
unlock(&.lock)
if != nil {
netpollgoready(, 3)
}
if != nil {
netpollgoready(, 3)
}
}
func ( *pollDesc) {
lock(&.lock)
if .closing {
throw("runtime: unblock on closing polldesc")
}
.closing = true
.rseq++
.wseq++
var , *g
atomic.StorepNoWB(noescape(unsafe.Pointer(&)), nil) // full memory barrier between store to closing and read of rg/wg in netpollunblock
= netpollunblock(, 'r', false)
= netpollunblock(, 'w', false)
if .rt.f != nil {
deltimer(&.rt)
.rt.f = nil
}
if .wt.f != nil {
deltimer(&.wt)
.wt.f = nil
}
unlock(&.lock)
if != nil {
netpollgoready(, 3)
}
if != nil {
netpollgoready(, 3)
}
}
func ( *gList, *pollDesc, int32) {
var , *g
if == 'r' || == 'r'+'w' {
= netpollunblock(, 'r', true)
}
if == 'w' || == 'r'+'w' {
= netpollunblock(, 'w', true)
}
if != nil {
.push()
}
if != nil {
.push()
}
}
func ( *pollDesc, int32) int {
if .closing {
return pollErrClosing
}
if ( == 'r' && .rd < 0) || ( == 'w' && .wd < 0) {
return pollErrTimeout
if == 'r' && .everr {
return pollErrNotPollable
}
return pollNoError
}
func ( *g, unsafe.Pointer) bool {
:= atomic.Casuintptr((*uintptr)(), pdWait, uintptr(unsafe.Pointer()))
atomic.Xadd(&netpollWaiters, 1)
}
return
}
func ( *g, int) {
atomic.Xadd(&netpollWaiters, -1)
goready(, +1)
}
if || netpollcheckerr(, ) == 0 {
gopark(netpollblockcommit, unsafe.Pointer(), waitReasonIOWait, traceEvGoBlockNet, 5)
unlock(&.lock)
return
}
var *g
if {
if .rd <= 0 || .rt.f == nil {
throw("runtime: inconsistent read deadline")
}
.rd = -1
atomic.StorepNoWB(unsafe.Pointer(&.rt.f), nil) // full memory barrier between store to rd and load of rg in netpollunblock
= netpollunblock(, 'r', false)
}
var *g
if {
if .wd <= 0 || .wt.f == nil && ! {
throw("runtime: inconsistent write deadline")
}
.wd = -1
atomic.StorepNoWB(unsafe.Pointer(&.wt.f), nil) // full memory barrier between store to wd and load of wg in netpollunblock
= netpollunblock(, 'w', false)
}
unlock(&.lock)
if != nil {
netpollgoready(, 0)
}
if != nil {
netpollgoready(, 0)
}
}
func ( interface{}, uintptr) {
netpolldeadlineimpl(.(*pollDesc), , true, true)
}
func ( interface{}, uintptr) {
netpolldeadlineimpl(.(*pollDesc), , true, false)
}
func ( interface{}, uintptr) {
netpolldeadlineimpl(.(*pollDesc), , false, true)
}
func ( *pollCache) () *pollDesc {
lock(&.lock)
if .first == nil {
const = unsafe.Sizeof(pollDesc{})
:= pollBlockSize /
if == 0 {
= 1
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |