2018-23-01 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libgo / go / runtime / netpoll_aix.go
blobda59f93f51a21bcc6f01725395180b20d71e793a
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 //go:noescape
38 //extern pollset_ctl
39 func pollset_ctl(ps pollset_t, pollctl_array *poll_ctl, array_length int32) int32
41 //go:noescape
42 //extern pollset_poll
43 func pollset_poll(ps pollset_t, polldata_array *pollfd, array_length int32, timeout int32) int32
45 //go:noescape
46 //extern pipe
47 func libc_pipe(fd *int32) int32
49 //extern __go_fcntl_uintptr
50 func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
52 func fcntl(fd, cmd int32, arg uintptr) uintptr {
53 r, _ := fcntlUintptr(uintptr(fd), uintptr(cmd), arg)
54 return r
57 var (
58 ps pollset_t = -1
59 mpfds map[int32]*pollDesc
60 pmtx mutex
61 rdwake int32
62 wrwake int32
63 needsUpdate bool
66 func netpollinit() {
67 var p [2]int32
69 if ps = pollset_create(-1); ps < 0 {
70 throw("runtime: netpollinit failed to create pollset")
72 // It is not possible to add or remove descriptors from
73 // the pollset while pollset_poll is active.
74 // We use a pipe to wakeup pollset_poll when the pollset
75 // needs to be updated.
76 if err := libc_pipe(&p[0]); err < 0 {
77 throw("runtime: netpollinit failed to create pipe")
79 rdwake = p[0]
80 wrwake = p[1]
82 fl := fcntl(rdwake, _F_GETFL, 0)
83 fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
84 fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
86 fl = fcntl(wrwake, _F_GETFL, 0)
87 fcntl(wrwake, _F_SETFL, fl|_O_NONBLOCK)
88 fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
90 // Add the read side of the pipe to the pollset.
91 var pctl poll_ctl
92 pctl.cmd = _PS_ADD
93 pctl.fd = rdwake
94 pctl.events = _POLLIN
95 if pollset_ctl(ps, &pctl, 1) != 0 {
96 throw("runtime: netpollinit failed to register pipe")
99 mpfds = make(map[int32]*pollDesc)
102 func netpolldescriptor() uintptr {
103 // ps is not a real file descriptor.
104 return ^uintptr(0)
107 func netpollopen(fd uintptr, pd *pollDesc) int32 {
108 // pollset_ctl will block if pollset_poll is active
109 // so wakeup pollset_poll first.
110 lock(&pmtx)
111 needsUpdate = true
112 unlock(&pmtx)
113 b := [1]byte{0}
114 write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
116 var pctl poll_ctl
117 pctl.cmd = _PS_ADD
118 pctl.fd = int32(fd)
119 pctl.events = _POLLIN | _POLLOUT
120 if pollset_ctl(ps, &pctl, 1) != 0 {
121 return int32(errno())
123 lock(&pmtx)
124 mpfds[int32(fd)] = pd
125 needsUpdate = false
126 unlock(&pmtx)
128 return 0
131 func netpollclose(fd uintptr) int32 {
132 // pollset_ctl will block if pollset_poll is active
133 // so wakeup pollset_poll first.
134 lock(&pmtx)
135 needsUpdate = true
136 unlock(&pmtx)
137 b := [1]byte{0}
138 write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
140 var pctl poll_ctl
141 pctl.cmd = _PS_DELETE
142 pctl.fd = int32(fd)
143 if pollset_ctl(ps, &pctl, 1) != 0 {
144 return int32(errno())
146 lock(&pmtx)
147 delete(mpfds, int32(fd))
148 needsUpdate = false
149 unlock(&pmtx)
151 return 0
154 func netpollarm(pd *pollDesc, mode int) {
155 throw("runtime: unused")
158 func netpoll(block bool) *g {
159 if ps == -1 {
160 return nil
162 timeout := int32(-1)
163 if !block {
164 timeout = 0
166 var pfds [128]pollfd
167 retry:
168 lock(&pmtx)
169 if needsUpdate {
170 unlock(&pmtx)
171 osyield()
172 goto retry
174 unlock(&pmtx)
175 nfound := pollset_poll(ps, &pfds[0], int32(len(pfds)), timeout)
176 if nfound < 0 {
177 e := errno()
178 if e != _EINTR {
179 throw("runtime: pollset_poll failed")
181 goto retry
183 var gp guintptr
184 for i := int32(0); i < nfound; i++ {
185 pfd := &pfds[i]
187 var mode int32
188 if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
189 if pfd.fd == rdwake {
190 var b [1]byte
191 read(pfd.fd, unsafe.Pointer(&b[0]), 1)
192 continue
194 mode += 'r'
196 if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
197 mode += 'w'
199 if mode != 0 {
200 lock(&pmtx)
201 pd := mpfds[pfd.fd]
202 unlock(&pmtx)
203 if pd != nil {
204 netpollready(&gp, pd, mode)
208 if block && gp == 0 {
209 goto retry
211 return gp.ptr()