github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/runtime/netpoll_aix.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime 6 7 import "github.com/x04/go/src/unsafe" 8 9 // This is based on the former libgo/runtime/netpoll_select.c implementation 10 // except that it uses poll instead of select and is written in Go. 11 // It's also based on Solaris implementation for the arming mechanisms 12 13 //go:cgo_import_dynamic libc_poll poll "libc.a/shr_64.o" 14 //go:linkname libc_poll libc_poll 15 16 var libc_poll libFunc 17 18 //go:nosplit 19 func poll(pfds *pollfd, npfds uintptr, timeout uintptr) (int32, int32) { 20 r, err := syscall3(&libc_poll, uintptr(unsafe.Pointer(pfds)), npfds, timeout) 21 return int32(r), int32(err) 22 } 23 24 // pollfd represents the poll structure for AIX operating system. 25 type pollfd struct { 26 fd int32 27 events int16 28 revents int16 29 } 30 31 const _POLLIN = 0x0001 32 const _POLLOUT = 0x0002 33 const _POLLHUP = 0x2000 34 const _POLLERR = 0x4000 35 36 var ( 37 pfds []pollfd 38 pds []*pollDesc 39 mtxpoll mutex 40 mtxset mutex 41 rdwake int32 42 wrwake int32 43 pendingUpdates int32 44 ) 45 46 func netpollinit() { 47 // Create the pipe we use to wakeup poll. 48 r, w, errno := nonblockingPipe() 49 if errno != 0 { 50 throw("netpollinit: failed to create pipe") 51 } 52 rdwake = r 53 wrwake = w 54 55 // Pre-allocate array of pollfd structures for poll. 56 pfds = make([]pollfd, 1, 128) 57 58 // Poll the read side of the pipe. 59 pfds[0].fd = rdwake 60 pfds[0].events = _POLLIN 61 62 pds = make([]*pollDesc, 1, 128) 63 pds[0] = nil 64 } 65 66 func netpollIsPollDescriptor(fd uintptr) bool { 67 return fd == uintptr(rdwake) || fd == uintptr(wrwake) 68 } 69 70 // netpollwakeup writes on wrwake to wakeup poll before any changes. 71 func netpollwakeup() { 72 if pendingUpdates == 0 { 73 pendingUpdates = 1 74 b := [1]byte{0} 75 write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1) 76 } 77 } 78 79 func netpollopen(fd uintptr, pd *pollDesc) int32 { 80 lock(&mtxpoll) 81 netpollwakeup() 82 83 lock(&mtxset) 84 unlock(&mtxpoll) 85 86 pd.user = uint32(len(pfds)) 87 pfds = append(pfds, pollfd{fd: int32(fd)}) 88 pds = append(pds, pd) 89 unlock(&mtxset) 90 return 0 91 } 92 93 func netpollclose(fd uintptr) int32 { 94 lock(&mtxpoll) 95 netpollwakeup() 96 97 lock(&mtxset) 98 unlock(&mtxpoll) 99 100 for i := 0; i < len(pfds); i++ { 101 if pfds[i].fd == int32(fd) { 102 pfds[i] = pfds[len(pfds)-1] 103 pfds = pfds[:len(pfds)-1] 104 105 pds[i] = pds[len(pds)-1] 106 pds[i].user = uint32(i) 107 pds = pds[:len(pds)-1] 108 break 109 } 110 } 111 unlock(&mtxset) 112 return 0 113 } 114 115 func netpollarm(pd *pollDesc, mode int) { 116 lock(&mtxpoll) 117 netpollwakeup() 118 119 lock(&mtxset) 120 unlock(&mtxpoll) 121 122 switch mode { 123 case 'r': 124 pfds[pd.user].events |= _POLLIN 125 case 'w': 126 pfds[pd.user].events |= _POLLOUT 127 } 128 unlock(&mtxset) 129 } 130 131 // netpollBreak interrupts an epollwait. 132 func netpollBreak() { 133 netpollwakeup() 134 } 135 136 // netpoll checks for ready network connections. 137 // Returns list of goroutines that become runnable. 138 // delay < 0: blocks indefinitely 139 // delay == 0: does not block, just polls 140 // delay > 0: block for up to that many nanoseconds 141 //go:nowritebarrierrec 142 func netpoll(delay int64) gList { 143 var timeout uintptr 144 if delay < 0 { 145 timeout = ^uintptr(0) 146 } else if delay == 0 { 147 // TODO: call poll with timeout == 0 148 return gList{} 149 } else if delay < 1e6 { 150 timeout = 1 151 } else if delay < 1e15 { 152 timeout = uintptr(delay / 1e6) 153 } else { 154 // An arbitrary cap on how long to wait for a timer. 155 // 1e9 ms == ~11.5 days. 156 timeout = 1e9 157 } 158 retry: 159 lock(&mtxpoll) 160 lock(&mtxset) 161 pendingUpdates = 0 162 unlock(&mtxpoll) 163 164 n, e := poll(&pfds[0], uintptr(len(pfds)), timeout) 165 if n < 0 { 166 if e != _EINTR { 167 println("errno=", e, " len(pfds)=", len(pfds)) 168 throw("poll failed") 169 } 170 unlock(&mtxset) 171 // If a timed sleep was interrupted, just return to 172 // recalculate how long we should sleep now. 173 if timeout > 0 { 174 return gList{} 175 } 176 goto retry 177 } 178 // Check if some descriptors need to be changed 179 if n != 0 && pfds[0].revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 { 180 if delay != 0 { 181 // A netpollwakeup could be picked up by a 182 // non-blocking poll. Only clear the wakeup 183 // if blocking. 184 var b [1]byte 185 for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 { 186 } 187 } 188 // Still look at the other fds even if the mode may have 189 // changed, as netpollBreak might have been called. 190 n-- 191 } 192 var toRun gList 193 for i := 1; i < len(pfds) && n > 0; i++ { 194 pfd := &pfds[i] 195 196 var mode int32 197 if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 { 198 mode += 'r' 199 pfd.events &= ^_POLLIN 200 } 201 if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 { 202 mode += 'w' 203 pfd.events &= ^_POLLOUT 204 } 205 if mode != 0 { 206 pds[i].everr = false 207 if pfd.revents == _POLLERR { 208 pds[i].everr = true 209 } 210 netpollready(&toRun, pds[i], mode) 211 n-- 212 } 213 } 214 unlock(&mtxset) 215 return toRun 216 }