1 // Copyright 2017 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.
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.
18 const _POLLIN = 0x0001
19 const _POLLOUT = 0x0002
20 const _POLLHUP = 0x2000
21 const _POLLERR = 0x4000
25 func libc_poll(pfds *pollfd, npfds uintptr, timeout uintptr) int32
29 func libc_pipe(fd *int32) int32
31 //extern __go_fcntl_uintptr
32 func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
34 func fcntl(fd, cmd int32, arg uintptr) uintptr {
35 r, _ := fcntlUintptr(uintptr(fd), uintptr(cmd), arg)
52 // Create the pipe we use to wakeup poll.
53 if err := libc_pipe(&p[0]); err < 0 {
54 throw("runtime: netpollinit failed to create pipe")
59 fl := fcntl(rdwake, _F_GETFL, 0)
60 fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
61 fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
63 fl = fcntl(wrwake, _F_GETFL, 0)
64 fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
66 // Pre-allocate array of pollfd structures for poll.
67 pfds = make([]pollfd, 1, 128)
68 // Poll the read side of the pipe.
70 pfds[0].events = _POLLIN
72 // Allocate index to pd array
73 pds = make([]*pollDesc, 1, 128)
77 func netpolldescriptor() uintptr {
81 func netpollwakeup() {
85 write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
89 func netpollopen(fd uintptr, pd *pollDesc) int32 {
96 pd.user = uint32(len(pfds))
99 pfds = append(pfds, pfd)
100 pds = append(pds, pd)
105 func netpollclose(fd uintptr) int32 {
112 for i := 0; i < len(pfds); i++ {
113 if pfds[i].fd == int32(fd) {
114 pfds[i] = pfds[len(pfds)-1]
115 pfds = pfds[:len(pfds)-1]
117 pds[i] = pds[len(pds)-1]
118 pds[i].user = uint32(i)
119 pds = pds[:len(pds)-1]
127 func netpollarm(pd *pollDesc, mode int) {
136 pfds[pd.user].events |= _POLLIN
138 pfds[pd.user].events |= _POLLOUT
143 //go:nowritebarrierrec
144 func netpoll(block bool) *g {
145 timeout := ^uintptr(0)
156 n := libc_poll(&pfds[0], uintptr(len(pfds)), timeout)
160 throw("runtime: poll failed")
165 // Check if some descriptors need to be changed
166 if n != 0 && pfds[0].revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
168 for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 {
170 // Do not look at the other fds in this case as the mode may have changed
171 // XXX only additions of flags are made, so maybe it is ok
176 for i := 0; i < len(pfds) && n > 0; i++ {
180 if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
182 pfd.events &= ^_POLLIN
184 if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
186 pfd.events &= ^_POLLOUT
189 netpollready(&gp, pds[i], mode)
194 if block && gp == 0 {