package runtime
import (
"runtime/internal/atomic"
"runtime/internal/syscall"
"unsafe"
)
var (
epfd int32 = -1
netpollBreakRd , netpollBreakWr uintptr
netpollWakeSig atomic .Uint32
)
func netpollinit () {
var errno uintptr
epfd , errno = syscall .EpollCreate1 (syscall .EPOLL_CLOEXEC )
if errno != 0 {
println ("runtime: epollcreate failed with" , errno )
throw ("runtime: netpollinit failed" )
}
r , w , errpipe := nonblockingPipe ()
if errpipe != 0 {
println ("runtime: pipe failed with" , -errpipe )
throw ("runtime: pipe failed" )
}
ev := syscall .EpollEvent {
Events : syscall .EPOLLIN ,
}
*(**uintptr )(unsafe .Pointer (&ev .Data )) = &netpollBreakRd
errno = syscall .EpollCtl (epfd , syscall .EPOLL_CTL_ADD , r , &ev )
if errno != 0 {
println ("runtime: epollctl failed with" , errno )
throw ("runtime: epollctl failed" )
}
netpollBreakRd = uintptr (r )
netpollBreakWr = uintptr (w )
}
func netpollIsPollDescriptor (fd uintptr ) bool {
return fd == uintptr (epfd ) || fd == netpollBreakRd || fd == netpollBreakWr
}
func netpollopen (fd uintptr , pd *pollDesc ) uintptr {
var ev syscall .EpollEvent
ev .Events = syscall .EPOLLIN | syscall .EPOLLOUT | syscall .EPOLLRDHUP | syscall .EPOLLET
tp := taggedPointerPack (unsafe .Pointer (pd ), pd .fdseq .Load ())
*(*taggedPointer )(unsafe .Pointer (&ev .Data )) = tp
return syscall .EpollCtl (epfd , syscall .EPOLL_CTL_ADD , int32 (fd ), &ev )
}
func netpollclose (fd uintptr ) uintptr {
var ev syscall .EpollEvent
return syscall .EpollCtl (epfd , syscall .EPOLL_CTL_DEL , int32 (fd ), &ev )
}
func netpollarm (pd *pollDesc , mode int ) {
throw ("runtime: unused" )
}
func netpollBreak () {
if !netpollWakeSig .CompareAndSwap (0 , 1 ) {
return
}
for {
var b byte
n := write (netpollBreakWr , unsafe .Pointer (&b ), 1 )
if n == 1 {
break
}
if n == -_EINTR {
continue
}
if n == -_EAGAIN {
return
}
println ("runtime: netpollBreak write failed with" , -n )
throw ("runtime: netpollBreak write failed" )
}
}
func netpoll (delay int64 ) gList {
if epfd == -1 {
return gList {}
}
var waitms int32
if delay < 0 {
waitms = -1
} else if delay == 0 {
waitms = 0
} else if delay < 1e6 {
waitms = 1
} else if delay < 1e15 {
waitms = int32 (delay / 1e6 )
} else {
waitms = 1e9
}
var events [128 ]syscall .EpollEvent
retry :
n , errno := syscall .EpollWait (epfd , events [:], int32 (len (events )), waitms )
if errno != 0 {
if errno != _EINTR {
println ("runtime: epollwait on fd" , epfd , "failed with" , errno )
throw ("runtime: netpoll failed" )
}
if waitms > 0 {
return gList {}
}
goto retry
}
var toRun gList
for i := int32 (0 ); i < n ; i ++ {
ev := events [i ]
if ev .Events == 0 {
continue
}
if *(**uintptr )(unsafe .Pointer (&ev .Data )) == &netpollBreakRd {
if ev .Events != syscall .EPOLLIN {
println ("runtime: netpoll: break fd ready for" , ev .Events )
throw ("runtime: netpoll: break fd ready for something unexpected" )
}
if delay != 0 {
var tmp [16 ]byte
read (int32 (netpollBreakRd ), noescape (unsafe .Pointer (&tmp [0 ])), int32 (len (tmp )))
netpollWakeSig .Store (0 )
}
continue
}
var mode int32
if ev .Events &(syscall .EPOLLIN |syscall .EPOLLRDHUP |syscall .EPOLLHUP |syscall .EPOLLERR ) != 0 {
mode += 'r'
}
if ev .Events &(syscall .EPOLLOUT |syscall .EPOLLHUP |syscall .EPOLLERR ) != 0 {
mode += 'w'
}
if mode != 0 {
tp := *(*taggedPointer )(unsafe .Pointer (&ev .Data ))
pd := (*pollDesc )(tp .pointer ())
tag := tp .tag ()
if pd .fdseq .Load () == tag {
pd .setEventErr (ev .Events == syscall .EPOLLERR , tag )
netpollready (&toRun , pd , mode )
}
}
}
return toRun
}
The pages are generated with Golds v0.6.7 . (GOOS=linux 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 .