runtime: use poll rather than pollset for netpoll on AIX
[platform/upstream/gcc.git] / libgo / go / runtime / netpoll_aix.go
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.
4
5 package runtime
6
7 import "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
12 type pollfd struct {
13         fd      int32
14         events  int16
15         revents int16
16 }
17
18 const _POLLIN = 0x0001
19 const _POLLOUT = 0x0002
20 const _POLLHUP = 0x2000
21 const _POLLERR = 0x4000
22
23 //go:noescape
24 //extern poll
25 func libc_poll(pfds *pollfd, npfds uintptr, timeout uintptr) int32
26
27 //go:noescape
28 //extern pipe
29 func libc_pipe(fd *int32) int32
30
31 //extern __go_fcntl_uintptr
32 func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
33
34 func fcntl(fd, cmd int32, arg uintptr) uintptr {
35         r, _ := fcntlUintptr(uintptr(fd), uintptr(cmd), arg)
36         return r
37 }
38
39 var (
40         pfds        []pollfd
41         pds         []*pollDesc
42         mtxpoll     mutex
43         mtxset      mutex
44         rdwake      int32
45         wrwake      int32
46         needsUpdate bool
47 )
48
49 func netpollinit() {
50         var p [2]int32
51
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")
55         }
56         rdwake = p[0]
57         wrwake = p[1]
58
59         fl := fcntl(rdwake, _F_GETFL, 0)
60         fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
61         fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
62
63         fl = fcntl(wrwake, _F_GETFL, 0)
64         fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
65
66         // Pre-allocate array of pollfd structures for poll.
67         pfds = make([]pollfd, 1, 128)
68         // Poll the read side of the pipe.
69         pfds[0].fd = rdwake
70         pfds[0].events = _POLLIN
71
72         // Allocate index to pd array
73         pds = make([]*pollDesc, 1, 128)
74         pds[0] = nil
75 }
76
77 func netpolldescriptor() uintptr {
78         return ^uintptr(0)
79 }
80
81 func netpollwakeup() {
82         if !needsUpdate {
83                 needsUpdate = true
84                 b := [1]byte{0}
85                 write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
86         }
87 }
88
89 func netpollopen(fd uintptr, pd *pollDesc) int32 {
90         lock(&mtxpoll)
91         netpollwakeup()
92
93         lock(&mtxset)
94         unlock(&mtxpoll)
95
96         pd.user = uint32(len(pfds))
97         var pfd pollfd
98         pfd.fd = int32(fd)
99         pfds = append(pfds, pfd)
100         pds = append(pds, pd)
101         unlock(&mtxset)
102         return 0
103 }
104
105 func netpollclose(fd uintptr) int32 {
106         lock(&mtxpoll)
107         netpollwakeup()
108
109         lock(&mtxset)
110         unlock(&mtxpoll)
111
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]
116
117                         pds[i] = pds[len(pds)-1]
118                         pds[i].user = uint32(i)
119                         pds = pds[:len(pds)-1]
120                         break
121                 }
122         }
123         unlock(&mtxset)
124         return 0
125 }
126
127 func netpollarm(pd *pollDesc, mode int) {
128         lock(&mtxpoll)
129         netpollwakeup()
130
131         lock(&mtxset)
132         unlock(&mtxpoll)
133
134         switch mode {
135         case 'r':
136                 pfds[pd.user].events |= _POLLIN
137         case 'w':
138                 pfds[pd.user].events |= _POLLOUT
139         }
140         unlock(&mtxset)
141 }
142
143 //go:nowritebarrierrec
144 func netpoll(block bool) *g {
145         timeout := ^uintptr(0)
146         if !block {
147                 timeout = 0
148                 return nil
149         }
150 retry:
151         lock(&mtxpoll)
152         lock(&mtxset)
153         needsUpdate = false
154         unlock(&mtxpoll)
155
156         n := libc_poll(&pfds[0], uintptr(len(pfds)), timeout)
157         if n < 0 {
158                 e := errno()
159                 if e != _EINTR {
160                         throw("runtime: poll failed")
161                 }
162                 unlock(&mtxset)
163                 goto retry
164         }
165         // Check if some descriptors need to be changed
166         if n != 0 && pfds[0].revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
167                 var b [1]byte
168                 for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 {
169                 }
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
172                 unlock(&mtxset)
173                 goto retry
174         }
175         var gp guintptr
176         for i := 0; i < len(pfds) && n > 0; i++ {
177                 pfd := &pfds[i]
178
179                 var mode int32
180                 if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
181                         mode += 'r'
182                         pfd.events &= ^_POLLIN
183                 }
184                 if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
185                         mode += 'w'
186                         pfd.events &= ^_POLLOUT
187                 }
188                 if mode != 0 {
189                         netpollready(&gp, pds[i], mode)
190                         n--
191                 }
192         }
193         unlock(&mtxset)
194         if block && gp == 0 {
195                 goto retry
196         }
197         return gp.ptr()
198 }