Commit 098c2172 by Ian Lance Taylor

runtime: better implementation of netpoll for AIX

    
    Reviewed-on: https://go-review.googlesource.com/54170

From-SVN: r251133
parent 8cca6c95
f02183eb66f5718769f3f6541dcc6744ae1771c0 152164a7249ecc5c2bfd4a091450dc7c2855f609
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -7,10 +7,10 @@ package runtime ...@@ -7,10 +7,10 @@ package runtime
import "unsafe" import "unsafe"
// This is based on the former libgo/runtime/netpoll_select.c implementation // 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. // except that it uses AIX pollset_poll instead of select and is written in Go.
type pollset_t int32
// 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 { type pollfd struct {
fd int32 fd int32
events int16 events int16
...@@ -22,8 +22,23 @@ const _POLLOUT = 0x0002 ...@@ -22,8 +22,23 @@ const _POLLOUT = 0x0002
const _POLLHUP = 0x2000 const _POLLHUP = 0x2000
const _POLLERR = 0x4000 const _POLLERR = 0x4000
//extern poll type poll_ctl struct {
func libc_poll(pfds *pollfd, npfds uintptr, timeout uintptr) int32 cmd int16
events int16
fd int32
}
const _PS_ADD = 0x0
const _PS_DELETE = 0x2
//extern pollset_create
func pollset_create(maxfd int32) pollset_t
//extern pollset_ctl
func pollset_ctl(ps pollset_t, pollctl_array *poll_ctl, array_length int32) int32
//extern pollset_poll
func pollset_poll(ps pollset_t, polldata_array *pollfd, array_length int32, timeout int32) int32
//extern pipe //extern pipe
func libc_pipe(fd *int32) int32 func libc_pipe(fd *int32) int32
...@@ -31,60 +46,100 @@ func libc_pipe(fd *int32) int32 ...@@ -31,60 +46,100 @@ func libc_pipe(fd *int32) int32
//extern __go_fcntl_uintptr //extern __go_fcntl_uintptr
func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr) func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
func closeonexec(fd int32) { func fcntl(fd, cmd int32, arg uintptr) uintptr {
fcntlUintptr(uintptr(fd), _F_SETFD, _FD_CLOEXEC) r, _ := fcntlUintptr(uintptr(fd), uintptr(cmd), arg)
return r
} }
var ( var (
allocated int ps pollset_t = -1
pfds []pollfd mpfds map[int32]*pollDesc
mpfds map[uintptr]*pollDesc pmtx mutex
pmtx mutex rdwake int32
rdwake int32 wrwake int32
wrwake int32 needsUpdate bool
) )
func netpollinit() { func netpollinit() {
var p [2]int32 var p [2]int32
// Create the pipe we use to wakeup poll. if ps = pollset_create(-1); ps < 0 {
throw("netpollinit: failed to create pollset")
}
// It is not possible to add or remove descriptors from
// the pollset while pollset_poll is active.
// We use a pipe to wakeup pollset_poll when the pollset
// needs to be updated.
if err := libc_pipe(&p[0]); err < 0 { if err := libc_pipe(&p[0]); err < 0 {
throw("netpollinit: failed to create pipe") throw("netpollinit: failed to create pipe")
} }
rdwake = p[0] rdwake = p[0]
wrwake = p[1] wrwake = p[1]
closeonexec(rdwake) fl := fcntl(rdwake, _F_GETFL, 0)
closeonexec(wrwake) fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
// Pre-allocate array of pollfd structures for poll.
allocated = 128 fl = fcntl(wrwake, _F_GETFL, 0)
pfds = make([]pollfd, allocated) fcntl(wrwake, _F_SETFL, fl|_O_NONBLOCK)
fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
// Add the read side of the pipe to the pollset.
var pctl poll_ctl
pctl.cmd = _PS_ADD
pctl.fd = rdwake
pctl.events = _POLLIN
if pollset_ctl(ps, &pctl, 1) != 0 {
throw("netpollinit: failed to register pipe")
}
mpfds = make(map[uintptr]*pollDesc) mpfds = make(map[int32]*pollDesc)
} }
func netpollopen(fd uintptr, pd *pollDesc) int32 { func netpollopen(fd uintptr, pd *pollDesc) int32 {
// pollset_ctl will block if pollset_poll is active
// so wakeup pollset_poll first.
lock(&pmtx) lock(&pmtx)
mpfds[fd] = pd needsUpdate = true
unlock(&pmtx) unlock(&pmtx)
// Wakeup poll.
b := [1]byte{0} b := [1]byte{0}
write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1) write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
var pctl poll_ctl
pctl.cmd = _PS_ADD
pctl.fd = int32(fd)
pctl.events = _POLLIN | _POLLOUT
if pollset_ctl(ps, &pctl, 1) != 0 {
return int32(errno())
}
lock(&pmtx)
mpfds[int32(fd)] = pd
needsUpdate = false
unlock(&pmtx)
return 0 return 0
} }
func netpollclose(fd uintptr) int32 { func netpollclose(fd uintptr) int32 {
// pollset_ctl will block if pollset_poll is active
// so wakeup pollset_poll first.
lock(&pmtx) lock(&pmtx)
delete(mpfds, fd) needsUpdate = true
unlock(&pmtx) unlock(&pmtx)
// Wakeup poll.
b := [1]byte{0} b := [1]byte{0}
write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1) write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
var pctl poll_ctl
pctl.cmd = _PS_DELETE
pctl.fd = int32(fd)
if pollset_ctl(ps, &pctl, 1) != 0 {
return int32(errno())
}
lock(&pmtx)
delete(mpfds, int32(fd))
needsUpdate = false
unlock(&pmtx)
return 0 return 0
} }
...@@ -93,62 +148,39 @@ func netpollarm(pd *pollDesc, mode int) { ...@@ -93,62 +148,39 @@ func netpollarm(pd *pollDesc, mode int) {
} }
func netpoll(block bool) *g { func netpoll(block bool) *g {
if allocated == 0 { if ps == -1 {
return nil return nil
} }
timeout := ^uintptr(0) timeout := int32(-1)
if !block { if !block {
timeout = 0 timeout = 0
} }
var pfds [128]pollfd
retry: retry:
lock(&pmtx) lock(&pmtx)
npfds := len(mpfds) + 1 if needsUpdate {
unlock(&pmtx) unlock(&pmtx)
osyield()
if npfds > allocated { goto retry
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) unlock(&pmtx)
nfound := pollset_poll(ps, &pfds[0], int32(len(pfds)), timeout)
n := libc_poll(&pfds[0], uintptr(npfds), timeout) if nfound < 0 {
if n < 0 {
e := errno() e := errno()
if e != _EINTR { if e != _EINTR {
throw("poll failed") throw("pollset_poll failed")
} }
goto retry goto retry
} }
var gp guintptr var gp guintptr
for i = 0; i < npfds && n > 0; i++ { for i := int32(0); i < nfound; i++ {
pfd := pfds[i] pfd := &pfds[i]
var mode int32 var mode int32
if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 { if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
if i == 0 { if pfd.fd == rdwake {
var b [1]byte var b [1]byte
read(pfd.fd, unsafe.Pointer(&b[0]), 1) read(pfd.fd, unsafe.Pointer(&b[0]), 1)
n--
continue continue
} }
mode += 'r' mode += 'r'
...@@ -158,12 +190,11 @@ retry: ...@@ -158,12 +190,11 @@ retry:
} }
if mode != 0 { if mode != 0 {
lock(&pmtx) lock(&pmtx)
pd := mpfds[uintptr(pfd.fd)] pd := mpfds[pfd.fd]
unlock(&pmtx) unlock(&pmtx)
if pd != nil { if pd != nil {
netpollready(&gp, pd, mode) netpollready(&gp, pd, mode)
} }
n--
} }
} }
if block && gp == 0 { if block && gp == 0 {
......
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