mirror of git://gcc.gnu.org/git/gcc.git
174 lines
3.2 KiB
Go
174 lines
3.2 KiB
Go
// Copyright 2017 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package runtime
|
|
|
|
import "unsafe"
|
|
|
|
// This is based on the former libgo/runtime/netpoll_select.c implementation
|
|
// except that it uses poll instead of select and is written in Go.
|
|
|
|
// These definitions should come from sysinfo.go as they may be OS-dependent.
|
|
// These are the definitions for the AIX operating system.
|
|
type pollfd struct {
|
|
fd int32
|
|
events int16
|
|
revents int16
|
|
}
|
|
|
|
const _POLLIN = 0x0001
|
|
const _POLLOUT = 0x0002
|
|
const _POLLHUP = 0x2000
|
|
const _POLLERR = 0x4000
|
|
|
|
//extern poll
|
|
func libc_poll(pfds *pollfd, npfds uintptr, timeout uintptr) int32
|
|
|
|
//extern pipe
|
|
func libc_pipe(fd *int32) int32
|
|
|
|
//extern __go_fcntl_uintptr
|
|
func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
|
|
|
|
func closeonexec(fd int32) {
|
|
fcntlUintptr(uintptr(fd), _F_SETFD, _FD_CLOEXEC)
|
|
}
|
|
|
|
var (
|
|
allocated int
|
|
pfds []pollfd
|
|
mpfds map[uintptr]*pollDesc
|
|
pmtx mutex
|
|
rdwake int32
|
|
wrwake int32
|
|
)
|
|
|
|
func netpollinit() {
|
|
var p [2]int32
|
|
|
|
// Create the pipe we use to wakeup poll.
|
|
if err := libc_pipe(&p[0]); err < 0 {
|
|
throw("netpollinit: failed to create pipe")
|
|
}
|
|
rdwake = p[0]
|
|
wrwake = p[1]
|
|
|
|
closeonexec(rdwake)
|
|
closeonexec(wrwake)
|
|
|
|
// Pre-allocate array of pollfd structures for poll.
|
|
allocated = 128
|
|
pfds = make([]pollfd, allocated)
|
|
|
|
mpfds = make(map[uintptr]*pollDesc)
|
|
}
|
|
|
|
func netpollopen(fd uintptr, pd *pollDesc) int32 {
|
|
lock(&pmtx)
|
|
mpfds[fd] = pd
|
|
unlock(&pmtx)
|
|
|
|
// Wakeup poll.
|
|
b := [1]byte{0}
|
|
write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
|
|
|
|
return 0
|
|
}
|
|
|
|
func netpollclose(fd uintptr) int32 {
|
|
lock(&pmtx)
|
|
delete(mpfds, fd)
|
|
unlock(&pmtx)
|
|
|
|
// Wakeup poll.
|
|
b := [1]byte{0}
|
|
write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
|
|
|
|
return 0
|
|
}
|
|
|
|
func netpollarm(pd *pollDesc, mode int) {
|
|
throw("unused")
|
|
}
|
|
|
|
func netpoll(block bool) *g {
|
|
if allocated == 0 {
|
|
return nil
|
|
}
|
|
timeout := ^uintptr(0)
|
|
if !block {
|
|
timeout = 0
|
|
}
|
|
retry:
|
|
lock(&pmtx)
|
|
npfds := len(mpfds) + 1
|
|
unlock(&pmtx)
|
|
|
|
if npfds > allocated {
|
|
for npfds > allocated {
|
|
allocated *= 2
|
|
}
|
|
pfds = make([]pollfd, allocated)
|
|
}
|
|
|
|
// Poll the read side of the pipe.
|
|
pfds[0].fd = rdwake
|
|
pfds[0].events = _POLLIN
|
|
lock(&pmtx)
|
|
// Notice that npfds may have changed since we released the lock.
|
|
// Just copy what we can, new descriptors will be added at next
|
|
// iteration.
|
|
i := 1
|
|
for fd := range mpfds {
|
|
if i >= allocated {
|
|
break
|
|
}
|
|
pfds[i].fd = int32(fd)
|
|
pfds[i].events = _POLLIN | _POLLOUT
|
|
i++
|
|
}
|
|
npfds = i
|
|
unlock(&pmtx)
|
|
|
|
n := libc_poll(&pfds[0], uintptr(npfds), timeout)
|
|
if n < 0 {
|
|
e := errno()
|
|
if e != _EINTR {
|
|
throw("poll failed")
|
|
}
|
|
goto retry
|
|
}
|
|
var gp guintptr
|
|
for i = 0; i < npfds && n > 0; i++ {
|
|
pfd := pfds[i]
|
|
|
|
var mode int32
|
|
if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
|
|
if i == 0 {
|
|
var b [1]byte
|
|
read(pfd.fd, unsafe.Pointer(&b[0]), 1)
|
|
n--
|
|
continue
|
|
}
|
|
mode += 'r'
|
|
}
|
|
if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
|
|
mode += 'w'
|
|
}
|
|
if mode != 0 {
|
|
lock(&pmtx)
|
|
pd := mpfds[uintptr(pfd.fd)]
|
|
unlock(&pmtx)
|
|
if pd != nil {
|
|
netpollready(&gp, pd, mode)
|
|
}
|
|
n--
|
|
}
|
|
}
|
|
if block && gp == 0 {
|
|
goto retry
|
|
}
|
|
return gp.ptr()
|
|
}
|