PR go/83787
[official-gcc.git] / libgo / go / runtime / netpoll_aix.go
blobb4962cc65900f07ffd6be05a78e521799cd627f9
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.
5 package runtime
7 import "unsafe"
9 // This is based on the former libgo/runtime/netpoll_select.c implementation
10 // except that it uses AIX pollset_poll instead of select and is written in Go.
12 type pollset_t int32
14 type pollfd struct {
15 fd int32
16 events int16
17 revents int16
20 const _POLLIN = 0x0001
21 const _POLLOUT = 0x0002
22 const _POLLHUP = 0x2000
23 const _POLLERR = 0x4000
25 type poll_ctl struct {
26 cmd int16
27 events int16
28 fd int32
31 const _PS_ADD = 0x0
32 const _PS_DELETE = 0x2
34 //extern pollset_create
35 func pollset_create(maxfd int32) pollset_t
37 //extern pollset_ctl
38 func pollset_ctl(ps pollset_t, pollctl_array *poll_ctl, array_length int32) int32
40 //extern pollset_poll
41 func pollset_poll(ps pollset_t, polldata_array *pollfd, array_length int32, timeout int32) int32
43 //extern pipe
44 func libc_pipe(fd *int32) int32
46 //extern __go_fcntl_uintptr
47 func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
49 func fcntl(fd, cmd int32, arg uintptr) uintptr {
50 r, _ := fcntlUintptr(uintptr(fd), uintptr(cmd), arg)
51 return r
54 var (
55 ps pollset_t = -1
56 mpfds map[int32]*pollDesc
57 pmtx mutex
58 rdwake int32
59 wrwake int32
60 needsUpdate bool
63 func netpollinit() {
64 var p [2]int32
66 if ps = pollset_create(-1); ps < 0 {
67 throw("runtime: netpollinit failed to create pollset")
69 // It is not possible to add or remove descriptors from
70 // the pollset while pollset_poll is active.
71 // We use a pipe to wakeup pollset_poll when the pollset
72 // needs to be updated.
73 if err := libc_pipe(&p[0]); err < 0 {
74 throw("runtime: netpollinit failed to create pipe")
76 rdwake = p[0]
77 wrwake = p[1]
79 fl := fcntl(rdwake, _F_GETFL, 0)
80 fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
81 fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
83 fl = fcntl(wrwake, _F_GETFL, 0)
84 fcntl(wrwake, _F_SETFL, fl|_O_NONBLOCK)
85 fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
87 // Add the read side of the pipe to the pollset.
88 var pctl poll_ctl
89 pctl.cmd = _PS_ADD
90 pctl.fd = rdwake
91 pctl.events = _POLLIN
92 if pollset_ctl(ps, &pctl, 1) != 0 {
93 throw("runtime: netpollinit failed to register pipe")
96 mpfds = make(map[int32]*pollDesc)
99 func netpolldescriptor() uintptr {
100 // ps is not a real file descriptor.
101 return ^uintptr(0)
104 func netpollopen(fd uintptr, pd *pollDesc) int32 {
105 // pollset_ctl will block if pollset_poll is active
106 // so wakeup pollset_poll first.
107 lock(&pmtx)
108 needsUpdate = true
109 unlock(&pmtx)
110 b := [1]byte{0}
111 write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
113 var pctl poll_ctl
114 pctl.cmd = _PS_ADD
115 pctl.fd = int32(fd)
116 pctl.events = _POLLIN | _POLLOUT
117 if pollset_ctl(ps, &pctl, 1) != 0 {
118 return int32(errno())
120 lock(&pmtx)
121 mpfds[int32(fd)] = pd
122 needsUpdate = false
123 unlock(&pmtx)
125 return 0
128 func netpollclose(fd uintptr) int32 {
129 // pollset_ctl will block if pollset_poll is active
130 // so wakeup pollset_poll first.
131 lock(&pmtx)
132 needsUpdate = true
133 unlock(&pmtx)
134 b := [1]byte{0}
135 write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
137 var pctl poll_ctl
138 pctl.cmd = _PS_DELETE
139 pctl.fd = int32(fd)
140 if pollset_ctl(ps, &pctl, 1) != 0 {
141 return int32(errno())
143 lock(&pmtx)
144 delete(mpfds, int32(fd))
145 needsUpdate = false
146 unlock(&pmtx)
148 return 0
151 func netpollarm(pd *pollDesc, mode int) {
152 throw("runtime: unused")
155 func netpoll(block bool) *g {
156 if ps == -1 {
157 return nil
159 timeout := int32(-1)
160 if !block {
161 timeout = 0
163 var pfds [128]pollfd
164 retry:
165 lock(&pmtx)
166 if needsUpdate {
167 unlock(&pmtx)
168 osyield()
169 goto retry
171 unlock(&pmtx)
172 nfound := pollset_poll(ps, &pfds[0], int32(len(pfds)), timeout)
173 if nfound < 0 {
174 e := errno()
175 if e != _EINTR {
176 throw("runtime: pollset_poll failed")
178 goto retry
180 var gp guintptr
181 for i := int32(0); i < nfound; i++ {
182 pfd := &pfds[i]
184 var mode int32
185 if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
186 if pfd.fd == rdwake {
187 var b [1]byte
188 read(pfd.fd, unsafe.Pointer(&b[0]), 1)
189 continue
191 mode += 'r'
193 if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
194 mode += 'w'
196 if mode != 0 {
197 lock(&pmtx)
198 pd := mpfds[pfd.fd]
199 unlock(&pmtx)
200 if pd != nil {
201 netpollready(&gp, pd, mode)
205 if block && gp == 0 {
206 goto retry
208 return gp.ptr()